Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Merge updates from trunk. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | globalStateCmd |
| Files: | files | file ages | folders |
| SHA1: |
0f3084cd16460f4ab336041499681eac |
| User & Date: | mistachkin 2014-08-13 20:09:26.780 |
Context
|
2014-08-28
| ||
| 05:54 | Merge updates from trunk. ... (check-in: 629891a775 user: mistachkin tags: optFor130, globalStateCmd) | |
|
2014-08-13
| ||
| 20:09 | Merge updates from trunk. ... (check-in: 0f3084cd16 user: mistachkin tags: globalStateCmd) | |
| 19:50 | Code styling and comment tweaks. ... (check-in: a3cf0e3390 user: mistachkin tags: trunk) | |
|
2014-07-24
| ||
| 03:15 | Merge from trunk. ... (check-in: 04cc3e2b49 user: mistachkin tags: globalStateCmd) | |
Changes
Changes to autosetup/jimsh0.c.
|
| | | 1 2 3 4 5 6 7 8 | /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */ #define _GNU_SOURCE #define JIM_TCL_COMPAT #define JIM_REFERENCES #define JIM_ANSIC #define JIM_REGEXP #define HAVE_NO_AUTOCONF #define _JIMAUTOCONF_H |
| ︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #define HAVE_UNISTD_H #endif #define JIM_VERSION 75 #ifndef JIM_WIN32COMPAT_H #define JIM_WIN32COMPAT_H #if defined(_WIN32) || defined(WIN32) #define HAVE_DLOPEN void *dlopen(const char *path, int mode); int dlclose(void *handle); | > > > > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
#define HAVE_UNISTD_H
#endif
#define JIM_VERSION 75
#ifndef JIM_WIN32COMPAT_H
#define JIM_WIN32COMPAT_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN32) || defined(WIN32)
#define HAVE_DLOPEN
void *dlopen(const char *path, int mode);
int dlclose(void *handle);
|
| ︙ | ︙ | |||
104 105 106 107 108 109 110 | struct dirent result; char *name; } DIR; DIR *opendir(const char *name); int closedir(DIR *dir); struct dirent *readdir(DIR *dir); | > > > > > | > > > > > > > > > > > > > > | 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 |
struct dirent result;
char *name;
} DIR;
DIR *opendir(const char *name);
int closedir(DIR *dir);
struct dirent *readdir(DIR *dir);
#elif defined(__MINGW32__)
#define strtod __strtod
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif
#ifndef UTF8_UTIL_H
#define UTF8_UTIL_H
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_UTF8_LEN 4
int utf8_fromunicode(char *p, unsigned uc);
#ifndef JIM_UTF8
#include <ctype.h>
#define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
#define utf8_getchars(CP, C) (*(CP) = (C), 1)
#define utf8_upper(C) toupper(C)
#define utf8_title(C) toupper(C)
#define utf8_lower(C) tolower(C)
#define utf8_index(C, I) (I)
#define utf8_charlen(C) 1
#define utf8_prev_len(S, L) 1
#else
#endif
#ifdef __cplusplus
}
#endif
#endif
#ifndef __JIM__H
#define __JIM__H
#ifdef __cplusplus
|
| ︙ | ︙ | |||
197 198 199 200 201 202 203 | #define JIM_EXIT 6 #define JIM_EVAL 7 #define JIM_MAX_CALLFRAME_DEPTH 1000 #define JIM_MAX_EVAL_DEPTH 2000 | | | | | | | | < < < < < < < < < | < | 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 |
#define JIM_EXIT 6
#define JIM_EVAL 7
#define JIM_MAX_CALLFRAME_DEPTH 1000
#define JIM_MAX_EVAL_DEPTH 2000
#define JIM_PRIV_FLAG_SHIFT 20
#define JIM_NONE 0
#define JIM_ERRMSG 1
#define JIM_ENUM_ABBREV 2
#define JIM_UNSHARED 4
#define JIM_MUSTEXIST 8
#define JIM_SUBST_NOVAR 1
#define JIM_SUBST_NOCMD 2
#define JIM_SUBST_NOESC 4
#define JIM_SUBST_FLAG 128
#define JIM_CASESENS 0
#define JIM_NOCASE 1
#define JIM_PATH_LEN 1024
#define JIM_NOTUSED(V) ((void) V)
#define JIM_LIBPATH "auto_path"
#define JIM_INTERACTIVE "tcl_interactive"
typedef struct Jim_Stack {
int len;
|
| ︙ | ︙ | |||
264 265 266 267 268 269 270 271 272 273 274 |
void (*keyDestructor)(void *privdata, void *key);
void (*valDestructor)(void *privdata, void *obj);
} Jim_HashTableType;
typedef struct Jim_HashTable {
Jim_HashEntry **table;
const Jim_HashTableType *type;
unsigned int size;
unsigned int sizemask;
unsigned int used;
unsigned int collisions;
| > | < > | | | | | | | | 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 |
void (*keyDestructor)(void *privdata, void *key);
void (*valDestructor)(void *privdata, void *obj);
} Jim_HashTableType;
typedef struct Jim_HashTable {
Jim_HashEntry **table;
const Jim_HashTableType *type;
void *privdata;
unsigned int size;
unsigned int sizemask;
unsigned int used;
unsigned int collisions;
unsigned int uniq;
} Jim_HashTable;
typedef struct Jim_HashTableIterator {
Jim_HashTable *ht;
Jim_HashEntry *entry, *nextEntry;
int index;
} Jim_HashTableIterator;
#define JIM_HT_INITIAL_SIZE 16
#define Jim_FreeEntryVal(ht, entry) \
if ((ht)->type->valDestructor) \
(ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
#define Jim_SetHashVal(ht, entry, _val_) do { \
if ((ht)->type->valDup) \
(entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \
else \
(entry)->u.val = (_val_); \
} while(0)
#define Jim_FreeEntryKey(ht, entry) \
if ((ht)->type->keyDestructor) \
(ht)->type->keyDestructor((ht)->privdata, (entry)->key)
#define Jim_SetHashKey(ht, entry, _key_) do { \
if ((ht)->type->keyDup) \
(entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \
else \
(entry)->key = (void *)(_key_); \
} while(0)
#define Jim_CompareHashKeys(ht, key1, key2) \
(((ht)->type->keyCompare) ? \
(ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \
(key1) == (key2))
#define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq)
#define Jim_GetHashEntryKey(he) ((he)->key)
#define Jim_GetHashEntryVal(he) ((he)->u.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;
|
| ︙ | ︙ | |||
339 340 341 342 343 344 345 |
struct {
void *ptr1;
void *ptr2;
} twoPtrValue;
struct {
| < > < > | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
struct {
void *ptr1;
void *ptr2;
} twoPtrValue;
struct {
struct Jim_Var *varPtr;
unsigned long callFrameId;
int global;
} varValue;
struct {
struct Jim_Obj *nsObj;
struct Jim_Cmd *cmdPtr;
unsigned long procEpoch;
} cmdValue;
struct {
struct Jim_Obj **ele;
int len;
int maxLen;
} listValue;
|
| ︙ | ︙ | |||
377 378 379 380 381 382 383 |
struct {
struct Jim_Obj *varNameObjPtr;
struct Jim_Obj *indexObjPtr;
} dictSubstValue;
struct {
| < > | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 |
struct {
struct Jim_Obj *varNameObjPtr;
struct Jim_Obj *indexObjPtr;
} dictSubstValue;
struct {
void *compre;
unsigned flags;
} regexpValue;
struct {
int line;
int argc;
} scriptLineValue;
} internalRep;
struct Jim_Obj *prevObjPtr;
|
| ︙ | ︙ | |||
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
Jim_Obj *procArgsObjPtr;
Jim_Obj *procBodyObjPtr;
struct Jim_CallFrame *next;
Jim_Obj *nsObj;
Jim_Obj *fileNameObj;
int line;
Jim_Stack *localCommands;
} Jim_CallFrame;
typedef struct Jim_Var {
Jim_Obj *objPtr;
struct Jim_CallFrame *linkFramePtr;
} Jim_Var;
| > > > | | | | | 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 |
Jim_Obj *procArgsObjPtr;
Jim_Obj *procBodyObjPtr;
struct Jim_CallFrame *next;
Jim_Obj *nsObj;
Jim_Obj *fileNameObj;
int line;
Jim_Stack *localCommands;
int tailcall;
struct Jim_Obj *tailcallObj;
struct Jim_Cmd *tailcallCmd;
} Jim_CallFrame;
typedef struct Jim_Var {
Jim_Obj *objPtr;
struct Jim_CallFrame *linkFramePtr;
} Jim_Var;
typedef int Jim_CmdProc(struct Jim_Interp *interp, int argc,
Jim_Obj *const *argv);
typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData);
typedef struct Jim_Cmd {
int inUse;
int isproc;
struct Jim_Cmd *prevCmd;
union {
struct {
Jim_CmdProc *cmdProc;
Jim_DelCmdProc *delProc;
void *privData;
} native;
struct {
Jim_Obj *argListObjPtr;
Jim_Obj *bodyObjPtr;
Jim_HashTable *staticVars;
|
| ︙ | ︙ | |||
587 588 589 590 591 592 593 |
typedef struct Jim_Reference {
Jim_Obj *objPtr;
Jim_Obj *finalizerCmdNamePtr;
char tag[JIM_REFERENCE_TAGLEN+1];
} Jim_Reference;
| < < < < > | 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 |
typedef struct Jim_Reference {
Jim_Obj *objPtr;
Jim_Obj *finalizerCmdNamePtr;
char tag[JIM_REFERENCE_TAGLEN+1];
} Jim_Reference;
#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
#define JIM_EXPORT
JIM_EXPORT void *Jim_Alloc (int size);
JIM_EXPORT void *Jim_Realloc(void *ptr, int size);
JIM_EXPORT void Jim_Free (void *ptr);
JIM_EXPORT char * Jim_StrDup (const char *s);
JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
JIM_EXPORT char **Jim_GetEnviron(void);
JIM_EXPORT void Jim_SetEnviron(char **env);
JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *template);
JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
|
| ︙ | ︙ | |||
737 738 739 740 741 742 743 |
JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
const char *name, Jim_Obj *objPtr);
JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
const char *name, const char *val);
JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
Jim_CallFrame *targetCallFrame);
| | | < | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 |
JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
const char *name, Jim_Obj *objPtr);
JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
const char *name, const char *val);
JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
Jim_CallFrame *targetCallFrame);
JIM_EXPORT Jim_Obj * Jim_MakeGlobalNamespaceName(Jim_Interp *interp,
Jim_Obj *nameObjPtr);
JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
Jim_Obj *nameObjPtr, int flags);
JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
Jim_Obj *nameObjPtr, int flags);
JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
const char *name, int flags);
JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
|
| ︙ | ︙ | |||
802 803 804 805 806 807 808 809 810 811 812 813 814 815 |
JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
JIM_EXPORT int Jim_DictValues(Jim_Interp *interp, Jim_Obj *dictObjPtr, Jim_Obj *patternObjPtr);
JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
int *intPtr);
JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
| > | 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 |
JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
JIM_EXPORT int Jim_DictValues(Jim_Interp *interp, Jim_Obj *dictObjPtr, Jim_Obj *patternObjPtr);
JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr);
JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
int *intPtr);
JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
|
| ︙ | ︙ | |||
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | 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_IsBigEndian(void); #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); | > < | 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 | 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_IsBigEndian(void); #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); JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr); JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr); #ifdef __cplusplus } |
| ︙ | ︙ | |||
901 902 903 904 905 906 907 | #define JIM_MODFLAG_HIDDEN 0x0001 #define JIM_MODFLAG_FULLARGV 0x0002 | | | < < < < | < | | < | 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 |
#define JIM_MODFLAG_HIDDEN 0x0001
#define JIM_MODFLAG_FULLARGV 0x0002
typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
typedef struct {
const char *cmd;
const char *args;
jim_subcmd_function *function;
short minargs;
short maxargs;
unsigned short flags;
} jim_subcmd_type;
const jim_subcmd_type *
Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
#ifdef __cplusplus
}
#endif
#endif
#ifndef JIMREGEXP_H
#define JIMREGEXP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
typedef struct {
int rm_so;
int rm_eo;
} regmatch_t;
|
| ︙ | ︙ | |||
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
};
int regcomp(regex_t *preg, const char *regex, int cflags);
int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
void regfree(regex_t *preg);
#endif
#endif
int Jim_bootstrapInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
return JIM_ERR;
| > > | 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 |
};
int regcomp(regex_t *preg, const char *regex, int cflags);
int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
void regfree(regex_t *preg);
#ifdef __cplusplus
}
#endif
#endif
int Jim_bootstrapInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
return JIM_ERR;
|
| ︙ | ︙ | |||
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
"\n"
"\n"
"\n"
"package require readdir\n"
"\n"
"\n"
"proc glob.globdir {dir pattern} {\n"
" set result {}\n"
" set files [readdir $dir]\n"
" lappend files . ..\n"
"\n"
" foreach name $files {\n"
" if {[string match $pattern $name]} {\n"
"\n"
| > > > > > | 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 |
"\n"
"\n"
"\n"
"package require readdir\n"
"\n"
"\n"
"proc glob.globdir {dir pattern} {\n"
" if {[file exists $dir/$pattern]} {\n"
"\n"
" return $pattern\n"
" }\n"
"\n"
" set result {}\n"
" set files [readdir $dir]\n"
" lappend files . ..\n"
"\n"
" foreach name $files {\n"
" if {[string match $pattern $name]} {\n"
"\n"
|
| ︙ | ︙ | |||
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 |
}
int Jim_stdlibInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG))
return JIM_ERR;
return Jim_EvalSource(interp, "stdlib.tcl", 1,
"\n"
"proc lambda {arglist args} {\n"
" tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
"}\n"
"\n"
"proc lambda.finalizer {name val} {\n"
" rename $name {}\n"
| > > | 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 |
}
int Jim_stdlibInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG))
return JIM_ERR;
return Jim_EvalSource(interp, "stdlib.tcl", 1,
"\n"
"\n"
"\n"
"proc lambda {arglist args} {\n"
" tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
"}\n"
"\n"
"proc lambda.finalizer {name val} {\n"
" rename $name {}\n"
|
| ︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 |
"proc function {value} {\n"
" return $value\n"
"}\n"
"\n"
"\n"
"\n"
"\n"
| | > | < | < | < < | < | | | > > > | > > > | 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 |
"proc function {value} {\n"
" return $value\n"
"}\n"
"\n"
"\n"
"\n"
"\n"
"proc stacktrace {{skip 0}} {\n"
" set trace {}\n"
" incr skip\n"
" foreach level [range $skip [info level]] {\n"
" lappend trace {*}[info frame -$level]\n"
" }\n"
" return $trace\n"
"}\n"
"\n"
"\n"
"proc stackdump {stacktrace} {\n"
" set lines {}\n"
" foreach {l f p} [lreverse $stacktrace] {\n"
" set line {}\n"
" if {$p ne \"\"} {\n"
" append line \"in procedure '$p' \"\n"
" if {$f ne \"\"} {\n"
" append line \"called \"\n"
" }\n"
" }\n"
" if {$f ne \"\"} {\n"
" append line \"at file \\\"$f\\\", line $l\"\n"
" }\n"
" if {$line ne \"\"} {\n"
" lappend lines $line\n"
" }\n"
" }\n"
" join $lines \\n\n"
"}\n"
"\n"
"\n"
"\n"
"proc errorInfo {msg {stacktrace \"\"}} {\n"
" if {$stacktrace eq \"\"} {\n"
"\n"
" set stacktrace [info stacktrace]\n"
"\n"
" lappend stacktrace {*}[stacktrace 1]\n"
" }\n"
" lassign $stacktrace p f l\n"
" if {$f ne \"\"} {\n"
" set result \"Runtime Error: $f:$l: \"\n"
" }\n"
" append result \"$msg\\n\"\n"
" append result [stackdump $stacktrace]\n"
|
| ︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 | " }\n" " }\n" " }\n" " return \"\"\n" "}\n" "\n" "\n" | | < | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
" }\n"
" }\n"
" }\n"
" return \"\"\n"
"}\n"
"\n"
"\n"
"proc {dict with} {&dictVar {args key} script} {\n"
" set keys {}\n"
" foreach {n v} [dict get $dictVar {*}$key] {\n"
" upvar $n var_$n\n"
" set var_$n $v\n"
" lappend keys $n\n"
" }\n"
" catch {uplevel 1 $script} msg opts\n"
" if {[info exists dictVar] && ([llength $key] == 0 || [dict exists $dictVar {*}$key])} {\n"
" foreach n $keys {\n"
" if {[info exists var_$n]} {\n"
" dict set dictVar {*}$key $n [set var_$n]\n"
" } else {\n"
" dict unset dictVar {*}$key $n\n"
" }\n"
" }\n"
" }\n"
" return {*}$opts $msg\n"
"}\n"
"\n"
"\n"
"proc {dict update} {&varName args script} {\n"
" set keys {}\n"
" foreach {n v} $args {\n"
" upvar $v var_$v\n"
" if {[dict exists $varName $n]} {\n"
" set var_$v [dict get $varName $n]\n"
" }\n"
" }\n"
" catch {uplevel 1 $script} msg opts\n"
" if {[info exists varName]} {\n"
" foreach {n v} $args {\n"
" if {[info exists var_$v]} {\n"
" dict set varName $n [set var_$v]\n"
" } else {\n"
" dict unset varName $n\n"
" }\n"
" }\n"
" }\n"
" return {*}$opts $msg\n"
"}\n"
"\n"
"\n"
"\n"
"proc {dict merge} {dict args} {\n"
" foreach d $args {\n"
"\n"
" dict size $d\n"
" foreach {k v} $d {\n"
" dict set dict $k $v\n"
" }\n"
" }\n"
" return $dict\n"
"}\n"
"\n"
"proc {dict replace} {dictionary {args {key value}}} {\n"
" if {[llength ${key value}] % 2} {\n"
" tailcall {dict replace}\n"
" }\n"
" tailcall dict merge $dictionary ${key value}\n"
"}\n"
"\n"
"\n"
"proc {dict lappend} {varName key {args value}} {\n"
" upvar $varName dict\n"
" if {[exists dict] && [dict exists $dict $key]} {\n"
" set list [dict get $dict $key]\n"
" }\n"
" lappend list {*}$value\n"
" dict set dict $key $list\n"
"}\n"
"\n"
"\n"
"proc {dict append} {varName key {args value}} {\n"
" upvar $varName dict\n"
" if {[exists dict] && [dict exists $dict $key]} {\n"
" set str [dict get $dict $key]\n"
" }\n"
" append str {*}$value\n"
" dict set dict $key $str\n"
"}\n"
"\n"
"\n"
"proc {dict incr} {varName key {increment 1}} {\n"
" upvar $varName dict\n"
" if {[exists dict] && [dict exists $dict $key]} {\n"
" set value [dict get $dict $key]\n"
" }\n"
" incr value $increment\n"
" dict set dict $key $value\n"
"}\n"
"\n"
"\n"
"proc {dict remove} {dictionary {args key}} {\n"
" foreach k $key {\n"
" dict unset dictionary $k\n"
" }\n"
" return $dictionary\n"
"}\n"
"\n"
"\n"
"proc {dict values} {dictionary {pattern *}} {\n"
" dict keys [lreverse $dictionary] $pattern\n"
"}\n"
"\n"
"\n"
"proc {dict for} {vars dictionary script} {\n"
" if {[llength $vars] != 2} {\n"
" return -code error \"must have exactly two variable names\"\n"
" }\n"
" dict size $dictionary\n"
" tailcall foreach $vars $dictionary $script\n"
"}\n"
);
}
int Jim_tclcompatInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG))
return JIM_ERR;
return Jim_EvalSource(interp, "tclcompat.tcl", 1,
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"set env [env]\n"
"\n"
"\n"
"if {[info commands stdout] ne \"\"} {\n"
"\n"
" foreach p {gets flush close eof seek tell} {\n"
" proc $p {chan args} {p} {\n"
" tailcall $chan $p {*}$args\n"
" }\n"
|
| ︙ | ︙ | |||
1453 1454 1455 1456 1457 1458 1459 | " return -code error \"fconfigure: unknown option $n\"\n" " }\n" " }\n" " }\n" " }\n" "}\n" "\n" | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 |
" return -code error \"fconfigure: unknown option $n\"\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}\n"
"\n"
"\n"
"proc fileevent {args} {\n"
" tailcall {*}$args\n"
"}\n"
"\n"
"\n"
"\n"
|
| ︙ | ︙ | |||
1527 1528 1529 1530 1531 1532 1533 |
" try {\n"
" if {$force ni {{} -force}} {\n"
" error \"bad option \\\"$force\\\": should be -force\"\n"
" }\n"
"\n"
" set in [open $source]\n"
"\n"
| | | | > > > > > > > > > > > > | 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 |
" try {\n"
" if {$force ni {{} -force}} {\n"
" error \"bad option \\\"$force\\\": should be -force\"\n"
" }\n"
"\n"
" set in [open $source]\n"
"\n"
" if {[file exists $target]} {\n"
" if {$force eq \"\"} {\n"
" error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
" }\n"
"\n"
" if {$source eq $target} {\n"
" return\n"
" }\n"
"\n"
"\n"
" file stat $source ss\n"
" file stat $target ts\n"
" if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
" return\n"
" }\n"
" }\n"
" set out [open $target w]\n"
" $in copyto $out\n"
" $out close\n"
" } on error {msg opts} {\n"
" incr opts(-level)\n"
" return {*}$opts $msg\n"
|
| ︙ | ︙ | |||
1578 1579 1580 1581 1582 1583 1584 | " $r close\n" " $w close\n" " error $error\n" " }\n" "}\n" "\n" "\n" | | | | | | | 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 |
" $r close\n"
" $w close\n"
" error $error\n"
" }\n"
"}\n"
"\n"
"\n"
"local proc pid {{channelId {}}} {\n"
" if {$channelId eq \"\"} {\n"
" tailcall upcall pid\n"
" }\n"
" if {[catch {$channelId tell}]} {\n"
" return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
" }\n"
" if {[catch {$channelId pid} pids]} {\n"
" return \"\"\n"
" }\n"
" return $pids\n"
"}\n"
"\n"
"\n"
"\n"
|
| ︙ | ︙ | |||
1678 1679 1680 1681 1682 1683 1684 | " }\n" " file delete $path\n" "}\n" ); } | < > > > > < | 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 | " }\n" " file delete $path\n" "}\n" ); } #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #include <sys/stat.h> #endif #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H) #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #ifdef HAVE_SYS_UN_H #include <sys/un.h> #endif #else #define JIM_ANSIC #endif |
| ︙ | ︙ | |||
1726 1727 1728 1729 1730 1731 1732 |
typedef struct AioFile
{
FILE *fp;
Jim_Obj *filename;
int type;
| | < < < | 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 |
typedef struct AioFile
{
FILE *fp;
Jim_Obj *filename;
int type;
int openFlags;
int fd;
Jim_Obj *rEvent;
Jim_Obj *wEvent;
Jim_Obj *eEvent;
int addr_family;
} AioFile;
static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
|
| ︙ | ︙ | |||
1758 1759 1760 1761 1762 1763 1764 |
static void JimAioDelProc(Jim_Interp *interp, void *privData)
{
AioFile *af = privData;
JIM_NOTUSED(interp);
| < < < < > > > > > | 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 |
static void JimAioDelProc(Jim_Interp *interp, void *privData)
{
AioFile *af = privData;
JIM_NOTUSED(interp);
Jim_DecrRefCount(interp, af->filename);
#ifdef jim_ext_eventloop
Jim_DeleteFileHandler(interp, af->fp, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
#endif
if (!(af->openFlags & AIO_KEEPOPEN)) {
fclose(af->fp);
}
Jim_Free(af);
}
static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
{
if (!ferror(af->fp)) {
return JIM_OK;
|
| ︙ | ︙ | |||
2018 2019 2020 2021 2022 2023 2024 |
Jim_SetResultInt(interp, feof(af->fp));
return JIM_OK;
}
static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
| > > > > > > | > > > > | > > > > > > > > > | 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 |
Jim_SetResultInt(interp, feof(af->fp));
return JIM_OK;
}
static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
if (argc == 3) {
#if !defined(JIM_ANSIC) && defined(HAVE_SHUTDOWN)
static const char * const options[] = { "r", "w", NULL };
enum { OPT_R, OPT_W, };
int option;
AioFile *af = Jim_CmdPrivData(interp);
if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
return JIM_ERR;
}
if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) {
return JIM_OK;
}
JimAioSetError(interp, NULL);
#else
Jim_SetResultString(interp, "async close not supported", -1);
#endif
return JIM_ERR;
}
return Jim_DeleteCommand(interp, Jim_String(argv[0]));
}
static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
int orig = SEEK_SET;
jim_wide offset;
|
| ︙ | ︙ | |||
2070 2071 2072 2073 2074 2075 2076 |
}
#ifdef O_NDELAY
static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
| | | < | 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 |
}
#ifdef O_NDELAY
static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
int fmode = fcntl(af->fd, F_GETFL);
if (argc) {
long nb;
if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
return JIM_ERR;
}
if (nb) {
fmode |= O_NDELAY;
}
else {
fmode &= ~O_NDELAY;
}
(void)fcntl(af->fd, F_SETFL, fmode);
}
Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0);
return JIM_OK;
}
#endif
static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
| ︙ | ︙ | |||
2193 2194 2195 2196 2197 2198 2199 |
return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, &af->wEvent, argc, argv);
}
static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
| | | 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 |
return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, &af->wEvent, argc, argv);
}
static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->eEvent, argc, argv);
}
#endif
static const jim_subcmd_type aio_command_table[] = {
{ "read",
"?-nonewline? ?len?",
aio_cmd_read,
|
| ︙ | ︙ | |||
2248 2249 2250 2251 2252 2253 2254 |
NULL,
aio_cmd_eof,
0,
0,
},
{ "close",
| < > < > | 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 |
NULL,
aio_cmd_eof,
0,
0,
},
{ "close",
"?r(ead)|w(rite)?",
aio_cmd_close,
0,
1,
JIM_MODFLAG_FULLARGV,
},
{ "seek",
"offset ?start|current|end",
aio_cmd_seek,
1,
|
| ︙ | ︙ | |||
2327 2328 2329 2330 2331 2332 2333 |
return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
}
static int JimAioOpenCommand(Jim_Interp *interp, int argc,
Jim_Obj *const *argv)
{
const char *mode;
| < < | > > > | | | | | | > | | > > | < < < < | | > | < | | | | | | | > | | | < < < > | > | > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
}
static int JimAioOpenCommand(Jim_Interp *interp, int argc,
Jim_Obj *const *argv)
{
const char *mode;
if (argc != 2 && argc != 3) {
Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?");
return JIM_ERR;
}
mode = (argc == 3) ? Jim_String(argv[2]) : "r";
#ifdef jim_ext_tclcompat
{
const char *filename = Jim_String(argv[1]);
if (*filename == '|') {
Jim_Obj *evalObj[3];
evalObj[0] = Jim_NewStringObj(interp, "::popen", -1);
evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
evalObj[2] = Jim_NewStringObj(interp, mode, -1);
return Jim_EvalObjVector(interp, 3, evalObj);
}
}
#endif
return JimMakeChannel(interp, NULL, -1, argv[1], "aio.handle%ld", 0, mode);
}
static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
const char *hdlfmt, int family, const char *mode)
{
AioFile *af;
char buf[AIO_CMD_LEN];
int openFlags = 0;
if (fh) {
filename = Jim_NewStringObj(interp, hdlfmt, -1);
openFlags = AIO_KEEPOPEN;
}
Jim_IncrRefCount(filename);
if (fh == NULL) {
#if !defined(JIM_ANSIC)
if (fd >= 0) {
fh = fdopen(fd, mode);
}
else
#endif
fh = fopen(Jim_String(filename), mode);
if (fh == NULL) {
JimAioSetError(interp, filename);
#if !defined(JIM_ANSIC)
if (fd >= 0) {
close(fd);
}
#endif
Jim_DecrRefCount(interp, filename);
return JIM_ERR;
}
}
af = Jim_Alloc(sizeof(*af));
memset(af, 0, sizeof(*af));
af->fp = fh;
af->fd = fileno(fh);
af->filename = filename;
#ifdef FD_CLOEXEC
if ((openFlags & AIO_KEEPOPEN) == 0) {
(void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
}
#endif
af->openFlags = openFlags;
af->addr_family = family;
snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, Jim_NewStringObj(interp, buf, -1)));
return JIM_OK;
}
static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename,
const char *hdlfmt, int family, const char *mode[2])
{
if (JimMakeChannel(interp, NULL, p[0], filename, hdlfmt, family, mode[0]) == JIM_OK) {
Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
if (JimMakeChannel(interp, NULL, p[1], filename, hdlfmt, family, mode[1]) == JIM_OK) {
Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
Jim_SetResult(interp, objPtr);
return JIM_OK;
}
}
close(p[0]);
close(p[1]);
JimAioSetError(interp, NULL);
return JIM_ERR;
}
int Jim_MakeTempFile(Jim_Interp *interp, const char *template)
{
#ifdef HAVE_MKSTEMP
int fd;
mode_t mask;
Jim_Obj *filenameObj;
if (template == NULL) {
const char *tmpdir = getenv("TMPDIR");
if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
tmpdir = "/tmp/";
}
filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
Jim_AppendString(interp, filenameObj, "/", 1);
}
Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
}
else {
filenameObj = Jim_NewStringObj(interp, template, -1);
}
mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
fd = mkstemp(filenameObj->bytes);
umask(mask);
if (fd < 0) {
Jim_SetResultString(interp, "Failed to create tempfile", -1);
Jim_FreeNewObj(interp, filenameObj);
return -1;
}
Jim_SetResult(interp, filenameObj);
return fd;
#else
Jim_SetResultString(interp, "tempfile not supported", -1);
return -1;
#endif
}
FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
{
Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
return ((AioFile *) cmdPtr->u.native.privData)->fp;
}
Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
return NULL;
}
|
| ︙ | ︙ | |||
2441 2442 2443 2444 2445 2446 2447 |
JimMakeChannel(interp, stdin, -1, NULL, "stdin", 0, "r");
JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w");
JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w");
return JIM_OK;
}
| < | 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 |
JimMakeChannel(interp, stdin, -1, NULL, "stdin", 0, "r");
JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w");
JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w");
return JIM_OK;
}
#include <errno.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_DIRENT_H
|
| ︙ | ︙ | |||
2477 2478 2479 2480 2481 2482 2483 |
if (dirPtr == NULL) {
if (nocomplain) {
return JIM_OK;
}
Jim_SetResultString(interp, strerror(errno), -1);
return JIM_ERR;
}
| < | | | | | | | | | | | < | | > > | > > > > > | 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 |
if (dirPtr == NULL) {
if (nocomplain) {
return JIM_OK;
}
Jim_SetResultString(interp, strerror(errno), -1);
return JIM_ERR;
}
else {
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
while ((entryPtr = readdir(dirPtr)) != NULL) {
if (entryPtr->d_name[0] == '.') {
if (entryPtr->d_name[1] == '\0') {
continue;
}
if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0'))
continue;
}
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, entryPtr->d_name, -1));
}
closedir(dirPtr);
Jim_SetResult(interp, listObj);
return JIM_OK;
}
}
int Jim_readdirInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "readdir", "1.0", JIM_ERRMSG))
return JIM_ERR;
Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
return JIM_OK;
}
#include <stdlib.h>
#include <string.h>
#if defined(JIM_REGEXP)
#else
#include <regex.h>
#endif
static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
{
regfree(objPtr->internalRep.regexpValue.compre);
Jim_Free(objPtr->internalRep.regexpValue.compre);
}
|
| ︙ | ︙ | |||
3056 3057 3058 3059 3060 3061 3062 |
else if (S_ISSOCK(mode)) {
return "socket";
}
#endif
return "unknown";
}
| | < < | < | < < < < < < < < < < < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > | > | | | > | | | | | > | | > > | < | | > | | 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 |
else if (S_ISSOCK(mode)) {
return "socket";
}
#endif
return "unknown";
}
static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *key, jim_wide value)
{
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1));
Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
}
static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb)
{
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
AppendStatElement(interp, listObj, "dev", sb->st_dev);
AppendStatElement(interp, listObj, "ino", sb->st_ino);
AppendStatElement(interp, listObj, "mode", sb->st_mode);
AppendStatElement(interp, listObj, "nlink", sb->st_nlink);
AppendStatElement(interp, listObj, "uid", sb->st_uid);
AppendStatElement(interp, listObj, "gid", sb->st_gid);
AppendStatElement(interp, listObj, "size", sb->st_size);
AppendStatElement(interp, listObj, "atime", sb->st_atime);
AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));
if (varName) {
Jim_Obj *objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
if (objPtr) {
if (Jim_DictSize(interp, objPtr) < 0) {
Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
Jim_FreeNewObj(interp, listObj);
return JIM_ERR;
}
if (Jim_IsShared(objPtr))
objPtr = Jim_DuplicateObj(interp, objPtr);
Jim_ListAppendList(interp, objPtr, listObj);
Jim_DictSize(interp, objPtr);
Jim_InvalidateStringRep(objPtr);
Jim_FreeNewObj(interp, listObj);
listObj = objPtr;
}
Jim_SetVariable(interp, varName, listObj);
}
Jim_SetResult(interp, listObj);
return JIM_OK;
}
static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
const char *path = Jim_String(argv[0]);
|
| ︙ | ︙ | |||
3262 3263 3264 3265 3266 3267 3268 |
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
return JIM_OK;
}
static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
{
| < < < | > | 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 |
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
return JIM_OK;
}
static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
{
Jim_SetResultBool(interp, access(Jim_String(filename), mode) != -1);
return JIM_OK;
}
static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
return file_access(interp, argv[0], R_OK);
}
static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
return file_access(interp, argv[0], W_OK);
}
static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
#ifdef X_OK
return file_access(interp, argv[0], X_OK);
#else
Jim_SetResultBool(interp, 1);
return JIM_OK;
#endif
}
static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
|
| ︙ | ︙ | |||
3389 3390 3391 3392 3393 3394 3395 |
return JIM_ERR;
}
argv++;
}
return JIM_OK;
}
| < < < < | < < | < < < < < < | 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 |
return JIM_ERR;
}
argv++;
}
return JIM_OK;
}
static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL);
if (fd < 0) {
return JIM_ERR;
}
close(fd);
return JIM_OK;
}
static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
const char *source;
const char *dest;
int force = 0;
|
| ︙ | ︙ | |||
3457 3458 3459 3460 3461 3462 3463 |
if (stat(path, sb) == -1) {
Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
return JIM_ERR;
}
return JIM_OK;
}
| | < < < > > > | 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 |
if (stat(path, sb) == -1) {
Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
return JIM_ERR;
}
return JIM_OK;
}
#ifdef HAVE_LSTAT
static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
{
const char *path = Jim_String(filename);
if (lstat(path, sb) == -1) {
Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
return JIM_ERR;
}
return JIM_OK;
}
#else
#define file_lstat file_stat
#endif
static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
struct stat sb;
if (file_stat(interp, argv[0], &sb) != JIM_OK) {
return JIM_ERR;
|
| ︙ | ︙ | |||
3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 |
if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
return JIM_ERR;
}
Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1);
return JIM_OK;
}
static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
struct stat sb;
if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
return JIM_ERR;
}
| > | > > > | | 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 |
if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
return JIM_ERR;
}
Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1);
return JIM_OK;
}
#ifdef HAVE_LSTAT
static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
struct stat sb;
if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
return JIM_ERR;
}
return StoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
}
#else
#define file_cmd_lstat file_cmd_stat
#endif
static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
struct stat sb;
if (file_stat(interp, argv[0], &sb) != JIM_OK) {
return JIM_ERR;
}
return StoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
}
static const jim_subcmd_type file_command_table[] = {
{ "atime",
"name",
file_cmd_atime,
1,
|
| ︙ | ︙ | |||
3725 3726 3727 3728 3729 3730 3731 |
{ "mkdir",
"dir ...",
file_cmd_mkdir,
1,
-1,
},
| < < | 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 |
{ "mkdir",
"dir ...",
file_cmd_mkdir,
1,
-1,
},
{ "tempfile",
"?template?",
file_cmd_tempfile,
0,
1,
},
{ "rename",
"?-force? source dest",
file_cmd_rename,
2,
3,
},
|
| ︙ | ︙ | |||
3758 3759 3760 3761 3762 3763 3764 |
"name",
file_cmd_size,
1,
1,
},
{ "stat",
| | < > | < > | 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 |
"name",
file_cmd_size,
1,
1,
},
{ "stat",
"name ?var?",
file_cmd_stat,
1,
2,
},
{ "lstat",
"name ?var?",
file_cmd_lstat,
1,
2,
},
{ "type",
"name",
file_cmd_type,
1,
|
| ︙ | ︙ | |||
3827 3828 3829 3830 3831 3832 3833 |
return JIM_ERR;
}
return JIM_OK;
}
static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
| < | | > | | 3973 3974 3975 3976 3977 3978 3979 3980 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 |
return JIM_ERR;
}
return JIM_OK;
}
static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
char *cwd = Jim_Alloc(MAXPATHLEN);
if (getcwd(cwd, MAXPATHLEN) == NULL) {
Jim_SetResultString(interp, "Failed to get pwd", -1);
Jim_Free(cwd);
return JIM_ERR;
}
#if defined(__MINGW32__) || defined(_MSC_VER)
{
char *p = cwd;
while ((p = strchr(p, '\\')) != NULL) {
*p++ = '/';
}
}
#endif
Jim_SetResultString(interp, cwd, -1);
Jim_Free(cwd);
return JIM_OK;
}
int Jim_fileInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "file", "1.0", JIM_ERRMSG))
return JIM_ERR;
|
| ︙ | ︙ | |||
3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 |
return JIM_OK;
}
int Jim_execInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
return JIM_ERR;
Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
return JIM_OK;
}
#else
#include <errno.h>
| > | 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 |
return JIM_OK;
}
int Jim_execInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
return JIM_ERR;
Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
return JIM_OK;
}
#else
#include <errno.h>
|
| ︙ | ︙ | |||
3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 |
static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env,
fdtype inputId, fdtype outputId, fdtype errorId);
static int JimErrno(void);
#else
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
typedef int fdtype;
typedef int pidtype;
#define JimPipe pipe
#define JimErrno() errno
#define JIM_BAD_FD -1
#define JIM_BAD_PID -1
| > | 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 |
static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env,
fdtype inputId, fdtype outputId, fdtype errorId);
static int JimErrno(void);
#else
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/stat.h>
typedef int fdtype;
typedef int pidtype;
#define JimPipe pipe
#define JimErrno() errno
#define JIM_BAD_FD -1
#define JIM_BAD_PID -1
|
| ︙ | ︙ | |||
4032 4033 4034 4035 4036 4037 4038 |
}
}
Jim_RemoveTrailingNewline(strObj);
fclose(fh);
return JIM_OK;
}
| < < < < < < < < < < < > | 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 |
}
}
Jim_RemoveTrailingNewline(strObj);
fclose(fh);
return JIM_OK;
}
static char **JimBuildEnv(Jim_Interp *interp)
{
int i;
int size;
int num;
int n;
char **envptr;
char *envdata;
Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
if (!objPtr) {
return Jim_GetEnviron();
}
num = Jim_ListLength(interp, objPtr);
if (num % 2) {
num--;
}
size = Jim_Length(objPtr) + 2;
envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
envdata = (char *)&envptr[num / 2 + 1];
|
| ︙ | ︙ | |||
4088 4089 4090 4091 4092 4093 4094 |
envdata++;
n++;
}
envptr[n] = NULL;
*envdata = 0;
return envptr;
| < < < < < | 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 |
envdata++;
n++;
}
envptr[n] = NULL;
*envdata = 0;
return envptr;
}
static void JimFreeEnv(char **env, char **original_environ)
{
if (env != original_environ) {
Jim_Free(env);
}
}
static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus)
{
Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
int rc = JIM_ERR;
|
| ︙ | ︙ | |||
4152 4153 4154 4155 4156 4157 4158 |
Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
return rc;
}
struct WaitInfo
{
| | | | | | 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 |
Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
return rc;
}
struct WaitInfo
{
pidtype pid;
int status;
int flags;
};
struct WaitInfoTable {
struct WaitInfo *info;
int size;
int used;
};
#define WI_DETACHED 2
#define WAIT_TABLE_GROW_BY 4
|
| ︙ | ︙ | |||
4187 4188 4189 4190 4191 4192 4193 |
table->size = table->used = 0;
return table;
}
static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
| | < | < | 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 |
table->size = table->used = 0;
return table;
}
static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
fdtype outputId;
fdtype errorId;
pidtype *pidPtr;
int numPids, result;
if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
Jim_Obj *listObj;
int i;
|
| ︙ | ︙ | |||
4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 |
return result;
}
static void JimReapDetachedPids(struct WaitInfoTable *table)
{
struct WaitInfo *waitPtr;
int count;
if (!table) {
return;
}
| > > > | | < < | > > > > > | 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 |
return result;
}
static void JimReapDetachedPids(struct WaitInfoTable *table)
{
struct WaitInfo *waitPtr;
int count;
int dest;
if (!table) {
return;
}
waitPtr = table->info;
dest = 0;
for (count = table->used; count > 0; waitPtr++, count--) {
if (waitPtr->flags & WI_DETACHED) {
int status;
pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG);
if (pid == waitPtr->pid) {
table->used--;
continue;
}
}
if (waitPtr != &table->info[dest]) {
table->info[dest] = *waitPtr;
}
dest++;
}
}
static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
{
int i;
|
| ︙ | ︙ | |||
4282 4283 4284 4285 4286 4287 4288 |
return pid;
}
}
return JIM_BAD_PID;
}
| < | 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 |
return pid;
}
}
return JIM_BAD_PID;
}
static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr)
{
int j;
struct WaitInfoTable *table = Jim_CmdPrivData(interp);
for (j = 0; j < numPids; j++) {
|
| ︙ | ︙ | |||
4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 |
Jim_SetResultErrno(interp, "couldn't create pipe");
goto error;
}
outputId = pipeIds[1];
}
#ifdef __MINGW32__
pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId);
if (pid == JIM_BAD_PID) {
Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
goto error;
}
#else
| > > > > > < < < < < < < < < > > > | | 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 |
Jim_SetResultErrno(interp, "couldn't create pipe");
goto error;
}
outputId = pipeIds[1];
}
if (pipe_dup_err) {
errorId = outputId;
}
#ifdef __MINGW32__
pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId);
if (pid == JIM_BAD_PID) {
Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
goto error;
}
#else
pid = vfork();
if (pid < 0) {
Jim_SetResultErrno(interp, "couldn't fork child process");
goto error;
}
if (pid == 0) {
if (inputId != -1) dup2(inputId, 0);
if (outputId != -1) dup2(outputId, 1);
if (errorId != -1) dup2(errorId, 2);
for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) {
close(i);
}
(void)signal(SIGPIPE, SIG_DFL);
execvpe(arg_array[firstArg], &arg_array[firstArg], Jim_GetEnviron());
fprintf(stderr, "couldn't exec \"%s\"\n", arg_array[firstArg]);
_exit(127);
}
#endif
if (table->used == table->size) {
|
| ︙ | ︙ | |||
4749 4750 4751 4752 4753 4754 4755 |
if (errorId != JIM_BAD_FD) {
JimRewindFd(errorId);
if (JimAppendStreamToString(interp, errorId, Jim_GetResult(interp)) != JIM_OK) {
result = JIM_ERR;
}
}
| | > > > > > | 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 |
if (errorId != JIM_BAD_FD) {
JimRewindFd(errorId);
if (JimAppendStreamToString(interp, errorId, Jim_GetResult(interp)) != JIM_OK) {
result = JIM_ERR;
}
}
Jim_RemoveTrailingNewline(Jim_GetResult(interp));
return result;
}
int Jim_execInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
return JIM_ERR;
#ifdef SIGPIPE
(void)signal(SIGPIPE, SIG_IGN);
#endif
Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable);
return JIM_OK;
}
#if defined(__MINGW32__)
|
| ︙ | ︙ | |||
5086 5087 5088 5089 5090 5091 5092 |
static pidtype
JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId)
{
STARTUPINFO startInfo;
PROCESS_INFORMATION procInfo;
HANDLE hProcess, h;
char execPath[MAX_PATH];
| < < | | 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 |
static pidtype
JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId)
{
STARTUPINFO startInfo;
PROCESS_INFORMATION procInfo;
HANDLE hProcess, h;
char execPath[MAX_PATH];
pidtype pid = JIM_BAD_PID;
Jim_Obj *cmdLineObj;
if (JimWinFindExecutable(argv[0], execPath) < 0) {
return JIM_BAD_PID;
}
argv[0] = execPath;
hProcess = GetCurrentProcess();
cmdLineObj = JimWinBuildCommandLine(interp, argv);
ZeroMemory(&startInfo, sizeof(startInfo));
startInfo.cb = sizeof(startInfo);
startInfo.dwFlags = STARTF_USESTDHANDLES;
startInfo.hStdInput = INVALID_HANDLE_VALUE;
startInfo.hStdOutput= INVALID_HANDLE_VALUE;
startInfo.hStdError = INVALID_HANDLE_VALUE;
if (inputId == JIM_BAD_FD) {
if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) {
CloseHandle(h);
}
|
| ︙ | ︙ | |||
5180 5181 5182 5183 5184 5185 5186 |
static int JimRewindFd(int fd)
{
return lseek(fd, 0L, SEEK_SET);
}
static int JimCreateTemp(Jim_Interp *interp, const char *contents, int len)
{
| | < | | 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 |
static int JimRewindFd(int fd)
{
return lseek(fd, 0L, SEEK_SET);
}
static int JimCreateTemp(Jim_Interp *interp, const char *contents, int len)
{
int fd = Jim_MakeTempFile(interp, NULL);
if (fd == JIM_BAD_FD) {
Jim_SetResultErrno(interp, "couldn't create temp file");
return -1;
}
unlink(Jim_String(Jim_GetResult(interp)));
if (contents) {
if (write(fd, contents, len) != len) {
Jim_SetResultErrno(interp, "couldn't write temp file");
close(fd);
return -1;
}
lseek(fd, 0L, SEEK_SET);
|
| ︙ | ︙ | |||
5215 5216 5217 5218 5219 5220 5221 |
JimFreeEnv(Jim_GetEnviron(), env);
Jim_SetEnviron(env);
}
#endif
#endif
| < | 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 |
JimFreeEnv(Jim_GetEnviron(), env);
Jim_SetEnviron(env);
}
#endif
#endif
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 500
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
|
| ︙ | ︙ | |||
5237 5238 5239 5240 5241 5242 5243 |
static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
char buf[100];
time_t t;
long seconds;
| | | > > > | 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 |
static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
char buf[100];
time_t t;
long seconds;
const char *format = "%a %b %d %H:%M:%S %Z %Y";
if (argc == 2 || (argc == 3 && !Jim_CompareStringImmediate(interp, argv[1], "-format"))) {
return -1;
}
if (argc == 3) {
format = Jim_String(argv[2]);
}
if (Jim_GetLong(interp, argv[0], &seconds) != JIM_OK) {
return JIM_ERR;
}
t = seconds;
if (strftime(buf, sizeof(buf), format, localtime(&t)) == 0) {
Jim_SetResultString(interp, "format string too long", -1);
return JIM_ERR;
}
Jim_SetResultString(interp, buf, -1);
return JIM_OK;
}
#ifdef HAVE_STRPTIME
|
| ︙ | ︙ | |||
5372 5373 5374 5375 5376 5377 5378 |
if (Jim_PackageProvide(interp, "clock", "1.0", JIM_ERRMSG))
return JIM_ERR;
Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
return JIM_OK;
}
| < > < | < < | < | < < | < > | | | | | | > | | 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 |
if (Jim_PackageProvide(interp, "clock", "1.0", JIM_ERRMSG))
return JIM_ERR;
Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
return JIM_OK;
}
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0);
return JIM_OK;
}
static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
Jim_Obj *patternObj;
if (!objPtr) {
return JIM_OK;
}
patternObj = (argc == 1) ? NULL : argv[1];
if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) {
if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) {
Jim_SetResult(interp, objPtr);
return JIM_OK;
}
}
return Jim_DictValues(interp, objPtr, patternObj);
}
static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
if (!objPtr) {
|
| ︙ | ︙ | |||
5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 |
if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
Jim_UnsetVariable(interp, argv[0], JIM_NONE);
return JIM_OK;
}
objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) {
return JIM_ERR;
}
resultObj = Jim_NewDictObj(interp, NULL, 0);
| > > > > > | 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 |
if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
Jim_UnsetVariable(interp, argv[0], JIM_NONE);
return JIM_OK;
}
objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
if (objPtr == NULL) {
return JIM_OK;
}
if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) {
return JIM_ERR;
}
resultObj = Jim_NewDictObj(interp, NULL, 0);
|
| ︙ | ︙ | |||
5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 |
}
}
Jim_SetResultInt(interp, len);
return JIM_OK;
}
static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
int i;
int len;
Jim_Obj *listObj = argv[1];
Jim_Obj *dictObj;
len = Jim_ListLength(interp, listObj);
if (len % 2) {
Jim_SetResultString(interp, "list must have an even number of elements", -1);
return JIM_ERR;
}
dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
if (!dictObj) {
return Jim_SetVariable(interp, argv[0], listObj);
}
if (Jim_IsShared(dictObj)) {
dictObj = Jim_DuplicateObj(interp, dictObj);
}
for (i = 0; i < len; i += 2) {
| > > > > > > > > > > > > > | 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 |
}
}
Jim_SetResultInt(interp, len);
return JIM_OK;
}
static int array_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
if (objPtr) {
return Jim_DictInfo(interp, objPtr);
}
Jim_SetResultFormatted(interp, "\"%#s\" isn't an array", argv[0], NULL);
return JIM_ERR;
}
static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
int i;
int len;
Jim_Obj *listObj = argv[1];
Jim_Obj *dictObj;
len = Jim_ListLength(interp, listObj);
if (len % 2) {
Jim_SetResultString(interp, "list must have an even number of elements", -1);
return JIM_ERR;
}
dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
if (!dictObj) {
return Jim_SetVariable(interp, argv[0], listObj);
}
else if (Jim_DictSize(interp, dictObj) < 0) {
return JIM_ERR;
}
if (Jim_IsShared(dictObj)) {
dictObj = Jim_DuplicateObj(interp, dictObj);
}
for (i = 0; i < len; i += 2) {
|
| ︙ | ︙ | |||
5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 |
},
{ "size",
"arrayName",
array_cmd_size,
1,
1,
},
{ "unset",
"arrayName ?pattern?",
array_cmd_unset,
1,
2,
| > > > > > > > | 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 |
},
{ "size",
"arrayName",
array_cmd_size,
1,
1,
},
{ "stat",
"arrayName",
array_cmd_stat,
1,
1,
},
{ "unset",
"arrayName ?pattern?",
array_cmd_unset,
1,
2,
|
| ︙ | ︙ | |||
5595 5596 5597 5598 5599 5600 5601 | Jim_execInit(interp); Jim_clockInit(interp); Jim_arrayInit(interp); Jim_stdlibInit(interp); Jim_tclcompatInit(interp); return JIM_OK; } | < | 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 | Jim_execInit(interp); Jim_clockInit(interp); Jim_arrayInit(interp); Jim_stdlibInit(interp); Jim_tclcompatInit(interp); return JIM_OK; } #define JIM_OPTIMIZATION #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> |
| ︙ | ︙ | |||
5659 5660 5661 5662 5663 5664 5665 | #define JIM_INTEGER_SPACE 24 const char *jim_tt_name(int type); #ifdef JIM_DEBUG_PANIC | | < | | 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 |
#define JIM_INTEGER_SPACE 24
const char *jim_tt_name(int type);
#ifdef JIM_DEBUG_PANIC
static void JimPanicDump(int fail_condition, const char *fmt, ...);
#define JimPanic(X) JimPanicDump X
#else
#define JimPanic(X)
#endif
static char JimEmptyStringRep[] = "";
static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action);
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,
|
| ︙ | ︙ | |||
5920 5921 5922 5923 5924 5925 5926 |
if (n > 0) {
n = utf8_strlen(s2, n);
}
return n;
}
#endif
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 |
if (n > 0) {
n = utf8_strlen(s2, n);
}
return n;
}
#endif
static int JimCheckConversion(const char *str, const char *endptr)
{
if (str[0] == '\0' || str == endptr) {
return JIM_ERR;
}
if (endptr[0] != '\0') {
|
| ︙ | ︙ | |||
6068 6069 6070 6071 6072 6073 6074 |
else {
*widePtr = jim_strtoull(str, &endptr);
}
return JimCheckConversion(str, endptr);
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 |
else {
*widePtr = jim_strtoull(str, &endptr);
}
return JimCheckConversion(str, endptr);
}
int Jim_StringToDouble(const char *str, double *doublePtr)
{
char *endptr;
errno = 0;
|
| ︙ | ︙ | |||
6131 6132 6133 6134 6135 6136 6137 |
for (i = 0; i < e; i++) {
res *= b;
}
return res;
}
#ifdef JIM_DEBUG_PANIC
| | | | | | | | 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 |
for (i = 0; i < e; i++) {
res *= b;
}
return res;
}
#ifdef JIM_DEBUG_PANIC
static void JimPanicDump(int condition, const char *fmt, ...)
{
va_list ap;
if (!condition) {
return;
}
va_start(ap, fmt);
fprintf(stderr, "\nJIM INTERPRETER PANIC: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n\n");
va_end(ap);
#ifdef HAVE_BACKTRACE
{
void *array[40];
int size, i;
char **strings;
size = backtrace(array, 40);
strings = backtrace_symbols(array, size);
for (i = 0; i < size; i++)
fprintf(stderr, "[backtrace] %s\n", strings[i]);
fprintf(stderr, "[backtrace] Include the above lines and the output\n");
fprintf(stderr, "[backtrace] of 'nm <executable>' in the bug report.\n");
}
#endif
exit(1);
}
#endif
|
| ︙ | ︙ | |||
6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 |
while (len--)
h += (h << 3) + *buf++;
return h;
}
static void JimResetHashTable(Jim_HashTable *ht)
{
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;
| > > > > > > | 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 |
while (len--)
h += (h << 3) + *buf++;
return h;
}
static void JimResetHashTable(Jim_HashTable *ht)
{
ht->table = NULL;
ht->size = 0;
ht->sizemask = 0;
ht->used = 0;
ht->collisions = 0;
#ifdef JIM_RANDOMISE_HASH
ht->uniq = (rand() ^ time(NULL) ^ clock());
#else
ht->uniq = 0;
#endif
}
static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter)
{
iter->ht = ht;
iter->index = -1;
iter->entry = NULL;
|
| ︙ | ︙ | |||
6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 |
if (size <= ht->used)
return;
Jim_InitHashTable(&n, ht->type, ht->privdata);
n.size = realsize;
n.sizemask = realsize - 1;
n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
n.used = ht->used;
for (i = 0; ht->used > 0; i++) {
Jim_HashEntry *he, *nextHe;
| > > | 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 |
if (size <= ht->used)
return;
Jim_InitHashTable(&n, ht->type, ht->privdata);
n.size = realsize;
n.sizemask = realsize - 1;
n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
n.uniq = ht->uniq;
memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
n.used = ht->used;
for (i = 0; ht->used > 0; i++) {
Jim_HashEntry *he, *nextHe;
|
| ︙ | ︙ | |||
6340 6341 6342 6343 6344 6345 6346 |
int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
{
int existed;
Jim_HashEntry *entry;
entry = JimInsertHashEntry(ht, key, 1);
if (entry->key) {
| > > > > | > | > > > < | 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 |
int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
{
int existed;
Jim_HashEntry *entry;
entry = JimInsertHashEntry(ht, key, 1);
if (entry->key) {
if (ht->type->valDestructor && ht->type->valDup) {
void *newval = ht->type->valDup(ht->privdata, val);
ht->type->valDestructor(ht->privdata, entry->u.val);
entry->u.val = newval;
}
else {
Jim_FreeEntryVal(ht, entry);
Jim_SetHashVal(ht, entry, val);
}
existed = 1;
}
else {
Jim_SetHashKey(ht, entry, key);
Jim_SetHashVal(ht, entry, val);
existed = 0;
}
return existed;
}
int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
{
|
| ︙ | ︙ | |||
6518 6519 6520 6521 6522 6523 6524 |
static unsigned int JimStringCopyHTHashFunction(const void *key)
{
return Jim_GenHashFunction(key, strlen(key));
}
static void *JimStringCopyHTDup(void *privdata, const void *key)
{
| | | 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 |
static unsigned int JimStringCopyHTHashFunction(const void *key)
{
return Jim_GenHashFunction(key, strlen(key));
}
static void *JimStringCopyHTDup(void *privdata, const void *key)
{
return Jim_StrDup(key);
}
static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2)
{
return strcmp(key1, key2) == 0;
}
|
| ︙ | ︙ | |||
6618 6619 6620 6621 6622 6623 6624 |
for (i = 0; i < stack->len; i++)
freeFunc(stack->vector[i]);
}
| | | 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 |
for (i = 0; i < stack->len; i++)
freeFunc(stack->vector[i]);
}
#define JIM_TT_NONE 0
#define JIM_TT_STR 1
#define JIM_TT_ESC 2
#define JIM_TT_VAR 3
#define JIM_TT_DICTSUGAR 4
#define JIM_TT_CMD 5
#define JIM_TT_SEP 6
|
| ︙ | ︙ | |||
6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 |
#define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
#define JIM_PS_DEF 0
#define JIM_PS_QUOTE 1
#define JIM_PS_DICTSUGAR 2
struct JimParserCtx
{
const char *p;
int len;
int linenr;
const char *tstart;
const char *tend;
int tline;
int tt;
int eof;
int state;
int comment;
| > > > > > < < < < | < < < | | | 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 |
#define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
#define JIM_PS_DEF 0
#define JIM_PS_QUOTE 1
#define JIM_PS_DICTSUGAR 2
struct JimParseMissing {
int ch;
int line;
};
struct JimParserCtx
{
const char *p;
int len;
int linenr;
const char *tstart;
const char *tend;
int tline;
int tt;
int eof;
int state;
int comment;
struct JimParseMissing missing;
};
static int JimParseScript(struct JimParserCtx *pc);
static int JimParseSep(struct JimParserCtx *pc);
static int JimParseEol(struct JimParserCtx *pc);
static int JimParseCmd(struct JimParserCtx *pc);
static int JimParseQuote(struct JimParserCtx *pc);
static int JimParseVar(struct JimParserCtx *pc);
static int JimParseBrace(struct JimParserCtx *pc);
static int JimParseStr(struct JimParserCtx *pc);
static int JimParseComment(struct JimParserCtx *pc);
static void JimParseSubCmd(struct JimParserCtx *pc);
static int JimParseSubQuote(struct JimParserCtx *pc);
static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
{
pc->p = prg;
pc->len = len;
pc->tstart = NULL;
pc->tend = NULL;
pc->tline = 0;
pc->tt = JIM_TT_NONE;
pc->eof = 0;
pc->state = JIM_PS_DEF;
pc->linenr = linenr;
pc->comment = 1;
pc->missing.ch = ' ';
pc->missing.line = linenr;
}
static int JimParseScript(struct JimParserCtx *pc)
{
while (1) {
if (!pc->len) {
pc->tstart = pc->p;
|
| ︙ | ︙ | |||
6835 6836 6837 6838 6839 6840 6841 |
case '\n':
pc->linenr++;
break;
}
pc->p++;
pc->len--;
}
| | | | 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 |
case '\n':
pc->linenr++;
break;
}
pc->p++;
pc->len--;
}
pc->missing.ch = '{';
pc->missing.line = pc->tline;
pc->tend = pc->p - 1;
}
static int JimParseSubQuote(struct JimParserCtx *pc)
{
int tt = JIM_TT_STR;
int line = pc->tline;
|
| ︙ | ︙ | |||
6882 6883 6884 6885 6886 6887 6888 |
case '$':
tt = JIM_TT_ESC;
break;
}
pc->p++;
pc->len--;
}
| | | | 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 |
case '$':
tt = JIM_TT_ESC;
break;
}
pc->p++;
pc->len--;
}
pc->missing.ch = '"';
pc->missing.line = line;
pc->tend = pc->p - 1;
return tt;
}
static void JimParseSubCmd(struct JimParserCtx *pc)
{
int level = 1;
|
| ︙ | ︙ | |||
6941 6942 6943 6944 6945 6946 6947 |
pc->linenr++;
break;
}
startofword = isspace(UCHAR(*pc->p));
pc->p++;
pc->len--;
}
| | | | 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 |
pc->linenr++;
break;
}
startofword = isspace(UCHAR(*pc->p));
pc->p++;
pc->len--;
}
pc->missing.ch = '[';
pc->missing.line = line;
pc->tend = pc->p - 1;
}
static int JimParseBrace(struct JimParserCtx *pc)
{
pc->tstart = pc->p + 1;
pc->tline = pc->linenr;
|
| ︙ | ︙ | |||
7086 7087 7088 7089 7090 7091 7092 |
return JimParseBrace(pc);
}
if (*pc->p == '"') {
pc->state = JIM_PS_QUOTE;
pc->p++;
pc->len--;
| | | > > > > | 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 |
return JimParseBrace(pc);
}
if (*pc->p == '"') {
pc->state = JIM_PS_QUOTE;
pc->p++;
pc->len--;
pc->missing.line = pc->tline;
}
}
pc->tstart = pc->p;
pc->tline = pc->linenr;
while (1) {
if (pc->len == 0) {
if (pc->state == JIM_PS_QUOTE) {
pc->missing.ch = '"';
}
pc->tend = pc->p - 1;
pc->tt = JIM_TT_ESC;
return JIM_OK;
}
switch (*pc->p) {
case '\\':
if (pc->state == JIM_PS_DEF && *(pc->p + 1) == '\n') {
pc->tend = pc->p - 1;
pc->tt = JIM_TT_ESC;
return JIM_OK;
}
if (pc->len >= 2) {
if (*(pc->p + 1) == '\n') {
pc->linenr++;
}
pc->p++;
pc->len--;
}
else if (pc->len == 1) {
pc->missing.ch = '\\';
}
break;
case '(':
if (pc->len > 1 && pc->p[1] != '$') {
break;
}
case ')':
|
| ︙ | ︙ | |||
7174 7175 7176 7177 7178 7179 7180 |
}
return JIM_OK;
}
static int JimParseComment(struct JimParserCtx *pc)
{
while (*pc->p) {
| | < < | | > > > > > > > > > > > | 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 |
}
return JIM_OK;
}
static int JimParseComment(struct JimParserCtx *pc)
{
while (*pc->p) {
if (*pc->p == '\\') {
pc->p++;
pc->len--;
if (pc->len == 0) {
pc->missing.ch = '\\';
return JIM_OK;
}
if (*pc->p == '\n') {
pc->linenr++;
}
}
else if (*pc->p == '\n') {
pc->p++;
pc->len--;
pc->linenr++;
break;
}
pc->p++;
pc->len--;
}
return JIM_OK;
}
|
| ︙ | ︙ | |||
7402 7403 7404 7405 7406 7407 7408 |
struct JimParserCtx parser;
JimParserInit(&parser, s, len, 1);
while (!parser.eof) {
JimParseScript(&parser);
}
if (stateCharPtr) {
| | | | 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 |
struct JimParserCtx parser;
JimParserInit(&parser, s, len, 1);
while (!parser.eof) {
JimParseScript(&parser);
}
if (stateCharPtr) {
*stateCharPtr = parser.missing.ch;
}
return parser.missing.ch == ' ';
}
static int JimParseListSep(struct JimParserCtx *pc);
static int JimParseListStr(struct JimParserCtx *pc);
static int JimParseListQuote(struct JimParserCtx *pc);
static int JimParseList(struct JimParserCtx *pc)
|
| ︙ | ︙ | |||
7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 |
if (objPtr->bytes == NULL) {
JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
objPtr->typePtr->updateStringProc(objPtr);
}
return objPtr->bytes;
}
static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
static const Jim_ObjType dictSubstObjType = {
"dict-substitution",
FreeDictSubstInternalRep,
| > > > > > > | 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 |
if (objPtr->bytes == NULL) {
JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
objPtr->typePtr->updateStringProc(objPtr);
}
return objPtr->bytes;
}
static void JimSetStringBytes(Jim_Obj *objPtr, const char *str)
{
objPtr->bytes = Jim_StrDup(str);
objPtr->length = strlen(str);
}
static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
static const Jim_ObjType dictSubstObjType = {
"dict-substitution",
FreeDictSubstInternalRep,
|
| ︙ | ︙ | |||
7701 7702 7703 7704 7705 7706 7707 |
};
static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
{
JIM_NOTUSED(interp);
dupPtr->internalRep.strValue.maxLength = srcPtr->length;
| < | 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 |
};
static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
{
JIM_NOTUSED(interp);
dupPtr->internalRep.strValue.maxLength = srcPtr->length;
dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
}
static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
{
if (objPtr->typePtr != &stringObjType) {
|
| ︙ | ︙ | |||
7750 7751 7752 7753 7754 7755 7756 |
if (len == -1)
len = strlen(s);
if (len == 0) {
objPtr->bytes = JimEmptyStringRep;
| < < > | 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 |
if (len == -1)
len = strlen(s);
if (len == 0) {
objPtr->bytes = JimEmptyStringRep;
}
else {
objPtr->bytes = Jim_Alloc(len + 1);
memcpy(objPtr->bytes, s, len);
objPtr->bytes[len] = '\0';
}
objPtr->length = len;
objPtr->typePtr = NULL;
return objPtr;
}
|
| ︙ | ︙ | |||
7789 7790 7791 7792 7793 7794 7795 |
}
Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
{
Jim_Obj *objPtr = Jim_NewObj(interp);
objPtr->bytes = s;
| | | 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 |
}
Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
{
Jim_Obj *objPtr = Jim_NewObj(interp);
objPtr->bytes = s;
objPtr->length = (len == -1) ? strlen(s) : len;
objPtr->typePtr = NULL;
return objPtr;
}
static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
{
int needlen;
|
| ︙ | ︙ | |||
7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 |
else {
objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
}
objPtr->internalRep.strValue.maxLength = needlen;
}
memcpy(objPtr->bytes + objPtr->length, str, len);
objPtr->bytes[objPtr->length + len] = '\0';
if (objPtr->internalRep.strValue.charLength >= 0) {
objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
}
objPtr->length += len;
}
| > < < < | | < < < | > > > | | | | < > | 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 |
else {
objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
}
objPtr->internalRep.strValue.maxLength = needlen;
}
memcpy(objPtr->bytes + objPtr->length, str, len);
objPtr->bytes[objPtr->length + len] = '\0';
if (objPtr->internalRep.strValue.charLength >= 0) {
objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
}
objPtr->length += len;
}
void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
{
JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
SetStringFromAny(interp, objPtr);
StringAppendString(objPtr, str, len);
}
void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
{
int len;
const char *str = Jim_GetString(appendObjPtr, &len);
Jim_AppendString(interp, objPtr, str, len);
}
void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
{
va_list ap;
SetStringFromAny(interp, objPtr);
va_start(ap, objPtr);
while (1) {
const char *s = va_arg(ap, const char *);
if (s == NULL)
break;
Jim_AppendString(interp, objPtr, s, -1);
}
va_end(ap);
}
int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
{
if (aObjPtr == bObjPtr) {
return 1;
}
else {
int Alen, Blen;
const char *sA = Jim_GetString(aObjPtr, &Alen);
const char *sB = Jim_GetString(bObjPtr, &Blen);
return Alen == Blen && memcmp(sA, sB, Alen) == 0;
}
}
int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
{
return JimGlobMatch(Jim_String(patternObjPtr), Jim_String(objPtr), nocase);
}
|
| ︙ | ︙ | |||
8034 8035 8036 8037 8038 8039 8040 |
}
static void JimStrCopyUpperLower(char *dest, const char *str, int uc)
{
while (*str) {
int c;
str += utf8_tounicode(str, &c);
| | | 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 |
}
static void JimStrCopyUpperLower(char *dest, const char *str, int uc)
{
while (*str) {
int c;
str += utf8_tounicode(str, &c);
dest += utf8_getchars(dest, uc ? utf8_upper(c) : utf8_lower(c));
}
*dest = 0;
}
static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
{
char *buf;
|
| ︙ | ︙ | |||
8094 8095 8096 8097 8098 8099 8100 |
}
#ifdef JIM_UTF8
len *= 2;
#endif
buf = p = Jim_Alloc(len + 1);
str += utf8_tounicode(str, &c);
| | | 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 |
}
#ifdef JIM_UTF8
len *= 2;
#endif
buf = p = Jim_Alloc(len + 1);
str += utf8_tounicode(str, &c);
p += utf8_getchars(p, utf8_title(c));
JimStrCopyUpperLower(p, str, 0);
return Jim_NewStringObjNoAlloc(interp, buf, -1);
}
static const char *utf8_memchr(const char *str, int len, int c)
|
| ︙ | ︙ | |||
8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 |
nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
if (nontrim == NULL) {
return Jim_NewEmptyStringObj(interp);
}
if (nontrim == strObjPtr->bytes + len) {
return strObjPtr;
}
if (Jim_IsShared(strObjPtr)) {
strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
}
else {
| > | 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 |
nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
if (nontrim == NULL) {
return Jim_NewEmptyStringObj(interp);
}
if (nontrim == strObjPtr->bytes + len) {
return strObjPtr;
}
if (Jim_IsShared(strObjPtr)) {
strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
}
else {
|
| ︙ | ︙ | |||
8224 8225 8226 8227 8228 8229 8230 |
{
Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
| > | < | | 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 |
{
Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
if (objPtr != strObjPtr && objPtr->refCount == 0) {
Jim_FreeNewObj(interp, objPtr);
}
return strObjPtr;
}
#ifdef HAVE_ISASCII
|
| ︙ | ︙ | |||
8268 8269 8270 8271 8272 8273 8274 |
if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
return JIM_ERR;
}
str = Jim_GetString(strObjPtr, &len);
if (len == 0) {
| | | | | 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 |
if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
return JIM_ERR;
}
str = Jim_GetString(strObjPtr, &len);
if (len == 0) {
Jim_SetResultBool(interp, !strict);
return JIM_OK;
}
switch (strclass) {
case STR_IS_INTEGER:
{
jim_wide w;
Jim_SetResultBool(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK);
return JIM_OK;
}
case STR_IS_DOUBLE:
{
double d;
Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
return JIM_OK;
}
case STR_IS_ALPHA: isclassfunc = isalpha; break;
case STR_IS_ALNUM: isclassfunc = isalnum; break;
case STR_IS_ASCII: isclassfunc = jim_isascii; break;
case STR_IS_DIGIT: isclassfunc = isdigit; break;
|
| ︙ | ︙ | |||
8305 8306 8307 8308 8309 8310 8311 |
case STR_IS_PUNCT: isclassfunc = ispunct; break;
default:
return JIM_ERR;
}
for (i = 0; i < len; i++) {
if (!isclassfunc(str[i])) {
| | | | > > | 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 |
case STR_IS_PUNCT: isclassfunc = ispunct; break;
default:
return JIM_ERR;
}
for (i = 0; i < len; i++) {
if (!isclassfunc(str[i])) {
Jim_SetResultBool(interp, 0);
return JIM_OK;
}
}
Jim_SetResultBool(interp, 1);
return JIM_OK;
}
static const Jim_ObjType comparedStringObjType = {
"compared-string",
NULL,
NULL,
NULL,
JIM_TYPE_REFERENCES,
};
int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
{
if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
return 1;
}
else {
const char *objStr = Jim_String(objPtr);
if (strcmp(str, objStr) != 0)
return 0;
if (objPtr->typePtr != &comparedStringObjType) {
Jim_FreeIntRep(interp, objPtr);
objPtr->typePtr = &comparedStringObjType;
}
objPtr->internalRep.ptr = (char *)str;
return 1;
}
|
| ︙ | ︙ | |||
8377 8378 8379 8380 8381 8382 8383 |
Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
}
static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
Jim_Obj *fileNameObj, int lineNumber)
{
JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
| | < < > < < | > < > < > > < < | < | 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 |
Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
}
static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
Jim_Obj *fileNameObj, int lineNumber)
{
JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typed object"));
Jim_IncrRefCount(fileNameObj);
objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
objPtr->internalRep.sourceValue.lineNumber = lineNumber;
objPtr->typePtr = &sourceObjType;
}
static const Jim_ObjType scriptLineObjType = {
"scriptline",
NULL,
NULL,
NULL,
JIM_NONE,
};
static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line)
{
Jim_Obj *objPtr;
#ifdef DEBUG_SHOW_SCRIPT
char buf[100];
snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc);
objPtr = Jim_NewStringObj(interp, buf, -1);
#else
objPtr = Jim_NewEmptyStringObj(interp);
#endif
objPtr->typePtr = &scriptLineObjType;
objPtr->internalRep.scriptLineValue.argc = argc;
objPtr->internalRep.scriptLineValue.line = line;
return objPtr;
}
static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
static int JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
static int JimParseCheckMissing(Jim_Interp *interp, int ch);
static const Jim_ObjType scriptObjType = {
"script",
FreeScriptInternalRep,
DupScriptInternalRep,
NULL,
JIM_TYPE_REFERENCES,
};
typedef struct ScriptToken
{
Jim_Obj *objPtr;
int type;
} ScriptToken;
typedef struct ScriptObj
{
ScriptToken *token;
Jim_Obj *fileNameObj;
int len;
int substFlags;
int inUse; /* Used to share a ScriptObj. Currently
only used by Jim_EvalObj() as protection against
shimmering of the currently evaluated object. */
int firstline;
int linenr;
} ScriptObj;
void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
{
int i;
struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
if (--script->inUse != 0)
return;
for (i = 0; i < script->len; i++) {
Jim_DecrRefCount(interp, script->token[i].objPtr);
}
Jim_Free(script->token);
Jim_DecrRefCount(interp, script->fileNameObj);
Jim_Free(script);
}
void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
{
JIM_NOTUSED(interp);
JIM_NOTUSED(srcPtr);
dupPtr->typePtr = NULL;
}
typedef struct
{
const char *token;
int len;
|
| ︙ | ︙ | |||
8664 8665 8666 8667 8668 8669 8670 |
if (lineargs == 0) {
token--;
}
script->len = token - script->token;
| | > > > > > > > > > > > > > > > > > > > > > > > > > | 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 |
if (lineargs == 0) {
token--;
}
script->len = token - script->token;
JimPanic((script->len >= count, "allocated script array is too short"));
#ifdef DEBUG_SHOW_SCRIPT
printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
for (i = 0; i < script->len; i++) {
const ScriptToken *t = &script->token[i];
printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
}
#endif
}
static int JimParseCheckMissing(Jim_Interp *interp, int ch)
{
const char *msg;
switch (ch) {
case '\\':
case ' ':
return JIM_OK;
case '[':
msg = "unmatched \"[\"";
break;
case '{':
msg = "missing close-brace";
break;
case '"':
default:
msg = "missing quote";
break;
}
Jim_SetResultString(interp, msg, -1);
return JIM_ERR;
}
static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
ParseTokenList *tokenlist)
{
int i;
struct ScriptToken *token;
|
| ︙ | ︙ | |||
8697 8698 8699 8700 8701 8702 8703 |
Jim_IncrRefCount(token->objPtr);
token++;
}
script->len = i;
}
| | > < < < < < | > > | | > > | 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 |
Jim_IncrRefCount(token->objPtr);
token++;
}
script->len = i;
}
static int JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
{
int scriptTextLen;
const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
struct JimParserCtx parser;
struct ScriptObj *script;
ParseTokenList tokenlist;
int line = 1;
int retcode = JIM_OK;
if (objPtr->typePtr == &sourceObjType) {
line = objPtr->internalRep.sourceValue.lineNumber;
}
ScriptTokenListInit(&tokenlist);
JimParserInit(&parser, scriptText, scriptTextLen, line);
while (!parser.eof) {
JimParseScript(&parser);
ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
parser.tline);
}
retcode = JimParseCheckMissing(interp, parser.missing.ch);
ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
script = Jim_Alloc(sizeof(*script));
memset(script, 0, sizeof(*script));
script->inUse = 1;
if (objPtr->typePtr == &sourceObjType) {
script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
}
else {
script->fileNameObj = interp->emptyObj;
}
script->linenr = parser.missing.line;
Jim_IncrRefCount(script->fileNameObj);
ScriptObjAddTokens(interp, script, &tokenlist);
ScriptTokenListFree(&tokenlist);
Jim_FreeIntRep(interp, objPtr);
Jim_SetIntRepPtr(objPtr, script);
objPtr->typePtr = &scriptObjType;
return retcode;
}
ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr)
{
if (objPtr == interp->emptyObj) {
objPtr = interp->nullScriptObj;
}
if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
if (JimSetScriptFromAny(interp, objPtr) == JIM_ERR) {
return NULL;
}
}
return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
}
static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
{
cmdPtr->inUse++;
|
| ︙ | ︙ | |||
8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 |
else if (Jim_Length(interp->framePtr->nsObj)) {
nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
Jim_AppendStrings(interp, nsObj, "::", name, NULL);
}
return nsObj;
}
static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr)
{
Jim_Obj *objPtr = interp->emptyObj;
if (name[0] == ':' && name[1] == ':') {
| > > > > > > > > > > > > > > > > | 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 |
else if (Jim_Length(interp->framePtr->nsObj)) {
nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
Jim_AppendStrings(interp, nsObj, "::", name, NULL);
}
return nsObj;
}
Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
{
Jim_Obj *resultObj;
const char *name = Jim_String(nameObjPtr);
if (name[0] == ':' && name[1] == ':') {
return nameObjPtr;
}
Jim_IncrRefCount(nameObjPtr);
resultObj = Jim_NewStringObj(interp, "::", -1);
Jim_AppendObj(interp, resultObj, nameObjPtr);
Jim_DecrRefCount(interp, nameObjPtr);
return resultObj;
}
static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr)
{
Jim_Obj *objPtr = interp->emptyObj;
if (name[0] == ':' && name[1] == ':') {
|
| ︙ | ︙ | |||
8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 |
#define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
#else
#define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
#define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
#endif
static int JimCreateCommand(Jim_Interp *interp, const char *name, Jim_Cmd *cmd)
{
Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, name);
if (he) {
Jim_InterpIncrProcEpoch(interp);
}
if (he && interp->local) {
| > > > > > | | | 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 |
#define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
#else
#define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
#define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
{
return nameObjPtr;
}
#endif
static int JimCreateCommand(Jim_Interp *interp, const char *name, Jim_Cmd *cmd)
{
Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, name);
if (he) {
Jim_InterpIncrProcEpoch(interp);
}
if (he && interp->local) {
cmd->prevCmd = Jim_GetHashEntryVal(he);
Jim_SetHashVal(&interp->commands, he, cmd);
}
else {
if (he) {
Jim_DeleteHashEntry(&interp->commands, name);
}
|
| ︙ | ︙ | |||
8931 8932 8933 8934 8935 8936 8937 |
if (len == 0) {
return JIM_OK;
}
cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
for (i = 0; i < len; i++) {
| | | | | | 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 |
if (len == 0) {
return JIM_OK;
}
cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
for (i = 0; i < len; i++) {
Jim_Obj *objPtr, *initObjPtr, *nameObjPtr;
Jim_Var *varPtr;
int subLen;
objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
subLen = Jim_ListLength(interp, objPtr);
if (subLen == 1 || subLen == 2) {
nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
if (subLen == 1) {
initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
if (initObjPtr == NULL) {
Jim_SetResultFormatted(interp,
"variable for initialization of static \"%#s\" not found in the local context",
nameObjPtr);
return JIM_ERR;
}
}
else {
initObjPtr = Jim_ListGetIndex(interp, objPtr, 1);
}
if (JimValidName(interp, "static variable", nameObjPtr) != JIM_OK) {
return JIM_ERR;
}
varPtr = Jim_Alloc(sizeof(*varPtr));
varPtr->objPtr = initObjPtr;
|
| ︙ | ︙ | |||
9036 9037 9038 9039 9040 9041 9042 |
for (i = 0; i < argListLen; i++) {
Jim_Obj *argPtr;
Jim_Obj *nameObjPtr;
Jim_Obj *defaultObjPtr;
int len;
| | | | | 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 |
for (i = 0; i < argListLen; i++) {
Jim_Obj *argPtr;
Jim_Obj *nameObjPtr;
Jim_Obj *defaultObjPtr;
int len;
argPtr = Jim_ListGetIndex(interp, argListObjPtr, i);
len = Jim_ListLength(interp, argPtr);
if (len == 0) {
Jim_SetResultString(interp, "argument with no name", -1);
err:
JimDecrCmdRefCount(interp, cmdPtr);
return NULL;
}
if (len > 2) {
Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
goto err;
}
if (len == 2) {
nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0);
defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1);
}
else {
nameObjPtr = argPtr;
defaultObjPtr = NULL;
}
|
| ︙ | ︙ | |||
9130 9131 9132 9133 9134 9135 9136 |
Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName);
}
else if (Jim_FindHashEntry(&interp->commands, fqnew)) {
Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
}
else {
| | | 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 |
Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName);
}
else if (Jim_FindHashEntry(&interp->commands, fqnew)) {
Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
}
else {
cmdPtr = Jim_GetHashEntryVal(he);
JimIncrCmdRefCount(cmdPtr);
JimUpdateProcNamespace(interp, cmdPtr, fqnew);
Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr);
Jim_DeleteHashEntry(&interp->commands, fqold);
|
| ︙ | ︙ | |||
9215 9216 9217 9218 9219 9220 9221 |
Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
}
return NULL;
}
#ifdef jim_ext_namespace
found:
#endif
| | | 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 |
Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
}
return NULL;
}
#ifdef jim_ext_namespace
found:
#endif
cmd = Jim_GetHashEntryVal(he);
Jim_FreeIntRep(interp, objPtr);
objPtr->typePtr = &commandObjType;
objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
objPtr->internalRep.cmdValue.cmdPtr = cmd;
objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
|
| ︙ | ︙ | |||
9321 9322 9323 9324 9325 9326 9327 |
}
}
Jim_FreeIntRep(interp, objPtr);
objPtr->typePtr = &variableObjType;
objPtr->internalRep.varValue.callFrameId = framePtr->id;
| | | 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 |
}
}
Jim_FreeIntRep(interp, objPtr);
objPtr->typePtr = &variableObjType;
objPtr->internalRep.varValue.callFrameId = framePtr->id;
objPtr->internalRep.varValue.varPtr = Jim_GetHashEntryVal(he);
objPtr->internalRep.varValue.global = global;
return JIM_OK;
}
static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
|
| ︙ | ︙ | |||
9639 9640 9641 9642 9643 9644 9645 |
else {
framePtr = interp->framePtr;
}
retval = Jim_DeleteHashEntry(&framePtr->vars, name);
if (retval == JIM_OK) {
| | | 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 |
else {
framePtr = interp->framePtr;
}
retval = Jim_DeleteHashEntry(&framePtr->vars, name);
if (retval == JIM_OK) {
framePtr->id = interp->callFrameEpoch++;
}
}
}
if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
}
return retval;
|
| ︙ | ︙ | |||
9723 9724 9725 9726 9727 9728 9729 |
dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
if (!dictObjPtr) {
return NULL;
}
ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
if (ret != JIM_OK) {
| < < | | < < < | | < < < | < < | < | 9881 9882 9883 9884 9885 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895 9896 9897 9898 9899 9900 9901 |
dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
if (!dictObjPtr) {
return NULL;
}
ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
if (ret != JIM_OK) {
Jim_SetResultFormatted(interp,
"can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr,
ret < 0 ? "variable isn't" : "no such element in");
}
else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr));
}
return resObjPtr;
}
static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
|
| ︙ | ︙ | |||
9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 |
static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj)
{
Jim_CallFrame *cf;
if (interp->freeFramesList) {
cf = interp->freeFramesList;
interp->freeFramesList = cf->next;
}
else {
cf = Jim_Alloc(sizeof(*cf));
| > > > > > > > > > > > > | > < < < < < < < < | < < < < < < < > | | | | | | | | > > | | | | < < < < | 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 |
static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj)
{
Jim_CallFrame *cf;
if (interp->freeFramesList) {
cf = interp->freeFramesList;
interp->freeFramesList = cf->next;
cf->argv = NULL;
cf->argc = 0;
cf->procArgsObjPtr = NULL;
cf->procBodyObjPtr = NULL;
cf->next = NULL;
cf->staticVars = NULL;
cf->localCommands = NULL;
cf->tailcall = 0;
cf->tailcallObj = NULL;
cf->tailcallCmd = NULL;
}
else {
cf = Jim_Alloc(sizeof(*cf));
memset(cf, 0, sizeof(*cf));
Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
}
cf->id = interp->callFrameEpoch++;
cf->parent = parent;
cf->level = parent ? parent->level + 1 : 0;
cf->nsObj = nsObj;
Jim_IncrRefCount(nsObj);
return cf;
}
static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
{
if (localCommands) {
Jim_Obj *cmdNameObj;
while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
Jim_HashEntry *he;
Jim_Obj *fqObjName;
Jim_HashTable *ht = &interp->commands;
const char *fqname = JimQualifyName(interp, Jim_String(cmdNameObj), &fqObjName);
he = Jim_FindHashEntry(ht, fqname);
if (he) {
Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
if (cmd->prevCmd) {
Jim_Cmd *prevCmd = cmd->prevCmd;
cmd->prevCmd = NULL;
JimDecrCmdRefCount(interp, cmd);
Jim_SetHashVal(ht, he, prevCmd);
}
else {
Jim_DeleteHashEntry(ht, fqname);
Jim_InterpIncrProcEpoch(interp);
}
}
Jim_DecrRefCount(interp, cmdNameObj);
JimFreeQualifiedName(interp, fqObjName);
}
Jim_FreeStack(localCommands);
Jim_Free(localCommands);
}
return JIM_OK;
}
#define JIM_FCF_FULL 0
#define JIM_FCF_REUSE 1
static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
{
JimDeleteLocalProcs(interp, cf->localCommands);
if (cf->procArgsObjPtr)
Jim_DecrRefCount(interp, cf->procArgsObjPtr);
if (cf->procBodyObjPtr)
Jim_DecrRefCount(interp, cf->procBodyObjPtr);
Jim_DecrRefCount(interp, cf->nsObj);
if (action == JIM_FCF_FULL || cf->vars.size != JIM_HT_INITIAL_SIZE)
Jim_FreeHashTable(&cf->vars);
else {
int i;
Jim_HashEntry **table = cf->vars.table, *he;
for (i = 0; i < JIM_HT_INITIAL_SIZE; i++) {
he = table[i];
while (he != NULL) {
Jim_HashEntry *nextEntry = he->next;
Jim_Var *varPtr = Jim_GetHashEntryVal(he);
Jim_DecrRefCount(interp, varPtr->objPtr);
Jim_Free(Jim_GetHashEntryKey(he));
Jim_Free(varPtr);
Jim_Free(he);
table[i] = NULL;
he = nextEntry;
}
}
cf->vars.used = 0;
}
cf->next = interp->freeFramesList;
interp->freeFramesList = cf;
}
#ifdef JIM_REFERENCES
static void JimReferencesHTValDestructor(void *interp, void *val)
{
|
| ︙ | ︙ | |||
10029 10030 10031 10032 10033 10034 10035 |
"reference",
NULL,
NULL,
UpdateStringOfReference,
JIM_TYPE_REFERENCES,
};
| | < < | < < < | | 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 |
"reference",
NULL,
NULL,
UpdateStringOfReference,
JIM_TYPE_REFERENCES,
};
static void UpdateStringOfReference(struct Jim_Obj *objPtr)
{
char buf[JIM_REFERENCE_SPACE + 1];
JimFormatReference(buf, objPtr->internalRep.refValue.refPtr, objPtr->internalRep.refValue.id);
JimSetStringBytes(objPtr, buf);
}
static int isrefchar(int c)
{
return (c == '_' || isalnum(c));
}
|
| ︙ | ︙ | |||
10094 10095 10096 10097 10098 10099 10100 |
goto badformat;
he = Jim_FindHashEntry(&interp->references, &value);
if (he == NULL) {
Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr);
return JIM_ERR;
}
| | | 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 |
goto badformat;
he = Jim_FindHashEntry(&interp->references, &value);
if (he == NULL) {
Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr);
return JIM_ERR;
}
refPtr = Jim_GetHashEntryVal(he);
Jim_FreeIntRep(interp, objPtr);
objPtr->typePtr = &referenceObjType;
objPtr->internalRep.refValue.id = value;
objPtr->internalRep.refValue.refPtr = refPtr;
return JIM_OK;
|
| ︙ | ︙ | |||
10277 10278 10279 10280 10281 10282 10283 |
Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
return i;
}
void Jim_FreeInterp(Jim_Interp *i)
{
| | > > > > > > > | < < < < < | | | | | | > > | > | < | | | < < < < | 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 |
Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
return i;
}
void Jim_FreeInterp(Jim_Interp *i)
{
Jim_CallFrame *cf, *cfx;
Jim_Obj *objPtr, *nextObjPtr;
for (cf = i->framePtr; cf; cf = cfx) {
cfx = cf->parent;
JimFreeCallFrame(i, cf, JIM_FCF_FULL);
}
Jim_DecrRefCount(i, i->emptyObj);
Jim_DecrRefCount(i, i->trueObj);
Jim_DecrRefCount(i, i->falseObj);
Jim_DecrRefCount(i, i->result);
Jim_DecrRefCount(i, i->stackTrace);
Jim_DecrRefCount(i, i->errorProc);
Jim_DecrRefCount(i, i->unknown);
Jim_DecrRefCount(i, i->errorFileNameObj);
Jim_DecrRefCount(i, i->currentScriptObj);
Jim_DecrRefCount(i, i->nullScriptObj);
Jim_FreeHashTable(&i->commands);
#ifdef JIM_REFERENCES
Jim_FreeHashTable(&i->references);
#endif
Jim_FreeHashTable(&i->packages);
Jim_Free(i->prngState);
Jim_FreeHashTable(&i->assocData);
#ifdef JIM_MAINTAINER
if (i->liveList != NULL) {
objPtr = i->liveList;
printf("\n-------------------------------------\n");
printf("Objects still in the free list:\n");
while (objPtr) {
const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
printf("%p (%d) %-10s: '%.20s...'\n",
(void *)objPtr, objPtr->refCount, type, objPtr->bytes);
}
else {
printf("%p (%d) %-10s: '%s'\n",
(void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
}
if (objPtr->typePtr == &sourceObjType) {
printf("FILE %s LINE %d\n",
Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
objPtr->internalRep.sourceValue.lineNumber);
}
objPtr = objPtr->nextObjPtr;
}
printf("-------------------------------------\n\n");
JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
}
#endif
objPtr = i->freeList;
while (objPtr) {
nextObjPtr = objPtr->nextObjPtr;
Jim_Free(objPtr);
objPtr = nextObjPtr;
}
for (cf = i->freeFramesList; cf; cf = cfx) {
cfx = cf->next;
if (cf->vars.table)
Jim_FreeHashTable(&cf->vars);
Jim_Free(cf);
}
Jim_Free(i);
}
Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
{
|
| ︙ | ︙ | |||
10453 10454 10455 10456 10457 10458 10459 |
if (len >= 3) {
if (Jim_Length(Jim_ListGetIndex(interp, interp->stackTrace, len - 2)) == 0) {
interp->addStackTrace = 1;
}
}
}
| < | 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 |
if (len >= 3) {
if (Jim_Length(Jim_ListGetIndex(interp, interp->stackTrace, len - 2)) == 0) {
interp->addStackTrace = 1;
}
}
}
static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
Jim_Obj *fileNameObj, int linenr)
{
if (strcmp(procname, "unknown") == 0) {
procname = "";
}
if (!*procname && !Jim_Length(fileNameObj)) {
|
| ︙ | ︙ | |||
10511 10512 10513 10514 10515 10516 10517 |
}
void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
{
Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
if (entryPtr != NULL) {
| | < | 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 |
}
void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
{
Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
if (entryPtr != NULL) {
AssocDataValue *assocEntryPtr = Jim_GetHashEntryVal(entryPtr);
return assocEntryPtr->data;
}
return NULL;
}
int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
{
|
| ︙ | ︙ | |||
10550 10551 10552 10553 10554 10555 10556 |
UpdateStringOfInt,
JIM_TYPE_NONE,
};
static void UpdateStringOfInt(struct Jim_Obj *objPtr)
{
| < > > > > > > > > > | > > > > > > | > > > > | > > > > > | > | | 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 |
UpdateStringOfInt,
JIM_TYPE_NONE,
};
static void UpdateStringOfInt(struct Jim_Obj *objPtr)
{
char buf[JIM_INTEGER_SPACE + 1];
jim_wide wideValue = JimWideValue(objPtr);
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;
JimSetStringBytes(objPtr, buf);
}
static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
{
jim_wide wideValue;
const char *str;
if (objPtr->typePtr == &coercedDoubleObjType) {
objPtr->typePtr = &intObjType;
|
| ︙ | ︙ | |||
10651 10652 10653 10654 10655 10656 10657 |
"double",
NULL,
NULL,
UpdateStringOfDouble,
JIM_TYPE_NONE,
};
| > > > > > > > > > | > | > > > > > > > > > > > > > > | > > | > > > > > | > > > > > > > > | > > > | | | > | | 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 |
"double",
NULL,
NULL,
UpdateStringOfDouble,
JIM_TYPE_NONE,
};
#ifndef HAVE_ISNAN
#undef isnan
#define isnan(X) ((X) != (X))
#endif
#ifndef HAVE_ISINF
#undef isinf
#define isinf(X) (1.0 / (X) == 0.0)
#endif
static void UpdateStringOfDouble(struct Jim_Obj *objPtr)
{
double value = objPtr->internalRep.doubleValue;
if (isnan(value)) {
JimSetStringBytes(objPtr, "NaN");
return;
}
if (isinf(value)) {
if (value < 0) {
JimSetStringBytes(objPtr, "-Inf");
}
else {
JimSetStringBytes(objPtr, "Inf");
}
return;
}
{
char buf[JIM_DOUBLE_SPACE + 1];
int i;
int len = sprintf(buf, "%.12g", value);
for (i = 0; i < len; i++) {
if (buf[i] == '.' || buf[i] == 'e') {
#if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
char *e = strchr(buf, 'e');
if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
e += 2;
memmove(e, e + 1, len - (e - buf));
}
#endif
break;
}
}
if (buf[i] == '\0') {
buf[i++] = '.';
buf[i++] = '0';
buf[i] = '\0';
}
JimSetStringBytes(objPtr, buf);
}
}
static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
{
double doubleValue;
jim_wide wideValue;
const char *str;
str = Jim_String(objPtr);
|
| ︙ | ︙ | |||
10874 10875 10876 10877 10878 10879 10880 |
}
}
return JIM_ELESTR_SIMPLE;
}
return JIM_ELESTR_QUOTE;
}
| | | | 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 |
}
}
return JIM_ELESTR_SIMPLE;
}
return JIM_ELESTR_QUOTE;
}
static int BackslashQuoteString(const char *s, int len, char *q)
{
char *p = q;
while (len--) {
switch (*s) {
case ' ':
case '$':
case '"':
case '[':
case ']':
case '{':
|
| ︙ | ︙ | |||
10994 10995 10996 10997 10998 10999 11000 |
realLength += len + 2;
break;
case JIM_ELESTR_QUOTE:
if (i == 0 && strRep[0] == '#') {
*p++ = '\\';
realLength++;
}
| | | 11198 11199 11200 11201 11202 11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 |
realLength += len + 2;
break;
case JIM_ELESTR_QUOTE:
if (i == 0 && strRep[0] == '#') {
*p++ = '\\';
realLength++;
}
qlen = BackslashQuoteString(strRep, len, p);
p += qlen;
realLength += qlen;
break;
}
if (i + 1 != objc) {
*p++ = ' ';
|
| ︙ | ︙ | |||
11030 11031 11032 11033 11034 11035 11036 |
Jim_Obj *fileNameObj;
int linenr;
if (objPtr->typePtr == &listObjType) {
return JIM_OK;
}
| | | 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 |
Jim_Obj *fileNameObj;
int linenr;
if (objPtr->typePtr == &listObjType) {
return JIM_OK;
}
if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) {
Jim_Obj **listObjPtrPtr;
int len;
int i;
listObjPtrPtr = JimDictPairs(objPtr, &len);
for (i = 0; i < len; i++) {
Jim_IncrRefCount(listObjPtrPtr[i]);
|
| ︙ | ︙ | |||
11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 |
jmp_buf jmpbuf;
Jim_Obj *command;
Jim_Interp *interp;
enum {
JIM_LSORT_ASCII,
JIM_LSORT_NOCASE,
JIM_LSORT_INTEGER,
JIM_LSORT_COMMAND
} type;
int order;
int index;
int indexed;
int (*subfn)(Jim_Obj **, Jim_Obj **);
};
static struct lsort_info *sort_info;
static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
{
| > > | 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 |
jmp_buf jmpbuf;
Jim_Obj *command;
Jim_Interp *interp;
enum {
JIM_LSORT_ASCII,
JIM_LSORT_NOCASE,
JIM_LSORT_INTEGER,
JIM_LSORT_REAL,
JIM_LSORT_COMMAND
} type;
int order;
int index;
int indexed;
int unique;
int (*subfn)(Jim_Obj **, Jim_Obj **);
};
static struct lsort_info *sort_info;
static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
{
|
| ︙ | ︙ | |||
11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 |
if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
longjmp(sort_info->jmpbuf, JIM_ERR);
}
return JimSign(lhs - rhs) * sort_info->order;
}
static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
{
Jim_Obj *compare_script;
int rc;
jim_wide ret = 0;
| > > > > > > > > > > > > > > > > > | 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 |
if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
longjmp(sort_info->jmpbuf, JIM_ERR);
}
return JimSign(lhs - rhs) * sort_info->order;
}
static int ListSortReal(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
{
double lhs = 0, rhs = 0;
if (Jim_GetDouble(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
Jim_GetDouble(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
longjmp(sort_info->jmpbuf, JIM_ERR);
}
if (lhs == rhs) {
return 0;
}
if (lhs > rhs) {
return sort_info->order;
}
return -sort_info->order;
}
static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
{
Jim_Obj *compare_script;
int rc;
jim_wide ret = 0;
|
| ︙ | ︙ | |||
11199 11200 11201 11202 11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 |
if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
longjmp(sort_info->jmpbuf, rc);
}
return JimSign(ret) * sort_info->order;
}
static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
{
struct lsort_info *prev_info;
typedef int (qsort_comparator) (const void *, const void *);
int (*fn) (Jim_Obj **, Jim_Obj **);
Jim_Obj **vector;
int len;
int rc;
| > > > > > > > > > > > > > > > > > > > > > > > > | > > > | > > > > | > | 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 |
if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
longjmp(sort_info->jmpbuf, rc);
}
return JimSign(ret) * sort_info->order;
}
static void ListRemoveDuplicates(Jim_Obj *listObjPtr, int (*comp)(Jim_Obj **lhs, Jim_Obj **rhs))
{
int src;
int dst = 0;
Jim_Obj **ele = listObjPtr->internalRep.listValue.ele;
for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) {
if (comp(&ele[dst], &ele[src]) == 0) {
Jim_DecrRefCount(sort_info->interp, ele[dst]);
}
else {
dst++;
}
ele[dst] = ele[src];
}
ele[++dst] = ele[src];
listObjPtr->internalRep.listValue.len = dst;
}
static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
{
struct lsort_info *prev_info;
typedef int (qsort_comparator) (const void *, const void *);
int (*fn) (Jim_Obj **, Jim_Obj **);
Jim_Obj **vector;
int len;
int rc;
JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object"));
SetListFromAny(interp, listObjPtr);
prev_info = sort_info;
sort_info = info;
vector = listObjPtr->internalRep.listValue.ele;
len = listObjPtr->internalRep.listValue.len;
switch (info->type) {
case JIM_LSORT_ASCII:
fn = ListSortString;
break;
case JIM_LSORT_NOCASE:
fn = ListSortStringNoCase;
break;
case JIM_LSORT_INTEGER:
fn = ListSortInteger;
break;
case JIM_LSORT_REAL:
fn = ListSortReal;
break;
case JIM_LSORT_COMMAND:
fn = ListSortCommand;
break;
default:
fn = NULL;
JimPanic((1, "ListSort called with invalid sort type"));
}
if (info->indexed) {
info->subfn = fn;
fn = ListSortIndexHelper;
}
if ((rc = setjmp(info->jmpbuf)) == 0) {
qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn);
if (info->unique && len > 1) {
ListRemoveDuplicates(listObjPtr, fn);
}
Jim_InvalidateStringRep(listObjPtr);
}
sort_info = prev_info;
return rc;
}
static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
{
|
| ︙ | ︙ | |||
11375 11376 11377 11378 11379 11380 11381 |
idx = listPtr->internalRep.listValue.len + idx;
Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
listPtr->internalRep.listValue.ele[idx] = newObjPtr;
Jim_IncrRefCount(newObjPtr);
return JIM_OK;
}
| | | 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 |
idx = listPtr->internalRep.listValue.len + idx;
Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
listPtr->internalRep.listValue.ele[idx] = newObjPtr;
Jim_IncrRefCount(newObjPtr);
return JIM_OK;
}
int Jim_ListSetIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
{
Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
int shared, i, idx;
varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED);
if (objPtr == NULL)
|
| ︙ | ︙ | |||
11423 11424 11425 11426 11427 11428 11429 |
Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen)
{
int i;
int listLen = Jim_ListLength(interp, listObjPtr);
Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp);
for (i = 0; i < listLen; ) {
| < < < | | 11678 11679 11680 11681 11682 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 |
Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen)
{
int i;
int listLen = Jim_ListLength(interp, listObjPtr);
Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp);
for (i = 0; i < listLen; ) {
Jim_AppendObj(interp, resObjPtr, Jim_ListGetIndex(interp, listObjPtr, i));
if (++i != listLen) {
Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
}
}
return resObjPtr;
}
|
| ︙ | ︙ | |||
11456 11457 11458 11459 11460 11461 11462 |
else {
int len = 0, objLen;
char *bytes, *p;
for (i = 0; i < objc; i++) {
| < | | | < > | | < | | > | 11708 11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 11740 11741 11742 11743 11744 11745 11746 11747 11748 11749 11750 11751 11752 11753 |
else {
int len = 0, objLen;
char *bytes, *p;
for (i = 0; i < objc; i++) {
len += Jim_Length(objv[i]);
}
if (objc)
len += objc - 1;
p = bytes = Jim_Alloc(len + 1);
for (i = 0; i < objc; i++) {
const char *s = Jim_GetString(objv[i], &objLen);
while (objLen && isspace(UCHAR(*s))) {
s++;
objLen--;
len--;
}
while (objLen && isspace(UCHAR(s[objLen - 1]))) {
if (objLen > 1 && s[objLen - 2] == '\\') {
break;
}
objLen--;
len--;
}
memcpy(p, s, objLen);
p += objLen;
if (i + 1 != objc) {
if (objLen)
*p++ = ' ';
else {
len--;
}
}
}
*p = '\0';
return Jim_NewStringObjNoAlloc(interp, bytes, len);
}
}
|
| ︙ | ︙ | |||
11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 |
return Jim_GenHashFunction((const unsigned char *)str, len);
}
static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
{
return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
}
static void JimObjectHTKeyValDestructor(void *interp, void *val)
{
Jim_DecrRefCount(interp, (Jim_Obj *)val);
}
static const Jim_HashTableType JimDictHashTableType = {
JimObjectHTHashFunction,
| > > > > > > < < > > | 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 |
return Jim_GenHashFunction((const unsigned char *)str, len);
}
static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
{
return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
}
static void *JimObjectHTKeyValDup(void *privdata, const void *val)
{
Jim_IncrRefCount((Jim_Obj *)val);
return (void *)val;
}
static void JimObjectHTKeyValDestructor(void *interp, void *val)
{
Jim_DecrRefCount(interp, (Jim_Obj *)val);
}
static const Jim_HashTableType JimDictHashTableType = {
JimObjectHTHashFunction,
JimObjectHTKeyValDup,
JimObjectHTKeyValDup,
JimObjectHTKeyCompare,
JimObjectHTKeyValDestructor,
JimObjectHTKeyValDestructor
};
static const Jim_ObjType dictObjType = {
"dict",
|
| ︙ | ︙ | |||
11578 11579 11580 11581 11582 11583 11584 |
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) {
| < < < < < | | 11835 11836 11837 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 |
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) {
Jim_AddHashEntry(dupHt, he->key, he->u.val);
}
dupPtr->internalRep.ptr = dupHt;
dupPtr->typePtr = &dictObjType;
}
static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len)
|
| ︙ | ︙ | |||
11605 11606 11607 11608 11609 11610 11611 |
ht = dictPtr->internalRep.ptr;
objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
JimInitHashTableIterator(ht, &htiter);
i = 0;
while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
| | | > > | > | | < < < < < < | < < < < < < < < < < | < < < < < < | | 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869 11870 11871 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 11895 11896 11897 11898 11899 11900 11901 11902 11903 11904 11905 11906 11907 11908 11909 11910 11911 11912 11913 11914 11915 11916 11917 11918 11919 11920 11921 11922 11923 11924 11925 11926 11927 11928 11929 11930 11931 11932 11933 11934 11935 11936 11937 11938 11939 11940 11941 11942 11943 11944 11945 11946 11947 11948 11949 11950 11951 11952 11953 |
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_GetHashEntryKey(he);
objv[i++] = Jim_GetHashEntryVal(he);
}
*len = i;
return objv;
}
static void UpdateStringOfDict(struct Jim_Obj *objPtr)
{
int len;
Jim_Obj **objv = JimDictPairs(objPtr, &len);
JimMakeListStringRep(objPtr, objv, len);
Jim_Free(objv);
}
static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
{
int listlen;
if (objPtr->typePtr == &dictObjType) {
return JIM_OK;
}
if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) {
Jim_String(objPtr);
}
listlen = Jim_ListLength(interp, objPtr);
if (listlen % 2) {
Jim_SetResultString(interp, "missing value to go with key", -1);
return JIM_ERR;
}
else {
Jim_HashTable *ht;
int i;
ht = Jim_Alloc(sizeof(*ht));
Jim_InitHashTable(ht, &JimDictHashTableType, interp);
for (i = 0; i < listlen; i += 2) {
Jim_Obj *keyObjPtr = Jim_ListGetIndex(interp, objPtr, i);
Jim_Obj *valObjPtr = Jim_ListGetIndex(interp, objPtr, i + 1);
Jim_ReplaceHashEntry(ht, keyObjPtr, valObjPtr);
}
Jim_FreeIntRep(interp, objPtr);
objPtr->typePtr = &dictObjType;
objPtr->internalRep.ptr = ht;
return JIM_OK;
}
}
static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
{
Jim_HashTable *ht = objPtr->internalRep.ptr;
if (valueObjPtr == NULL) {
return Jim_DeleteHashEntry(ht, keyObjPtr);
}
Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr);
return JIM_OK;
}
int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
{
JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
return JIM_ERR;
}
Jim_InvalidateStringRep(objPtr);
return DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
}
Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
{
Jim_Obj *objPtr;
int i;
|
| ︙ | ︙ | |||
11837 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 |
if (newObjPtr == NULL) {
goto err;
}
objPtr = Jim_NewDictObj(interp, NULL, 0);
DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
}
}
Jim_InvalidateStringRep(objPtr);
Jim_InvalidateStringRep(varObjPtr);
if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
goto err;
}
Jim_SetResult(interp, varObjPtr);
return JIM_OK;
| > | 12070 12071 12072 12073 12074 12075 12076 12077 12078 12079 12080 12081 12082 12083 12084 |
if (newObjPtr == NULL) {
goto err;
}
objPtr = Jim_NewDictObj(interp, NULL, 0);
DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
}
}
Jim_InvalidateStringRep(objPtr);
Jim_InvalidateStringRep(varObjPtr);
if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
goto err;
}
Jim_SetResult(interp, varObjPtr);
return JIM_OK;
|
| ︙ | ︙ | |||
11862 11863 11864 11865 11866 11867 11868 |
"index",
NULL,
NULL,
UpdateStringOfIndex,
JIM_TYPE_NONE,
};
| | | | | > > | | < < > | > | | < < | | | > | | 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105 12106 12107 12108 12109 12110 12111 12112 12113 12114 12115 12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 12128 |
"index",
NULL,
NULL,
UpdateStringOfIndex,
JIM_TYPE_NONE,
};
static void UpdateStringOfIndex(struct Jim_Obj *objPtr)
{
if (objPtr->internalRep.intValue == -1) {
JimSetStringBytes(objPtr, "end");
}
else {
char buf[JIM_INTEGER_SPACE + 1];
if (objPtr->internalRep.intValue >= 0) {
sprintf(buf, "%d", objPtr->internalRep.intValue);
}
else {
sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
}
JimSetStringBytes(objPtr, buf);
}
}
static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
{
int idx, end = 0;
const char *str;
char *endptr;
str = Jim_String(objPtr);
|
| ︙ | ︙ | |||
11951 11952 11953 11954 11955 11956 11957 |
int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
{
if (objPtr->typePtr == &intObjType) {
jim_wide val = JimWideValue(objPtr);
| | > > > > | | < | 12186 12187 12188 12189 12190 12191 12192 12193 12194 12195 12196 12197 12198 12199 12200 12201 12202 12203 12204 12205 12206 |
int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
{
if (objPtr->typePtr == &intObjType) {
jim_wide val = JimWideValue(objPtr);
if (val < 0)
*indexPtr = -INT_MAX;
else if (val > INT_MAX)
*indexPtr = INT_MAX;
else
*indexPtr = (int)val;
return JIM_OK;
}
if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
return JIM_ERR;
*indexPtr = objPtr->internalRep.intValue;
return JIM_OK;
}
|
| ︙ | ︙ | |||
11978 11979 11980 11981 11982 11983 11984 |
"exit",
"eval",
NULL
};
#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
| < < | | 12216 12217 12218 12219 12220 12221 12222 12223 12224 12225 12226 12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 |
"exit",
"eval",
NULL
};
#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
static const Jim_ObjType returnCodeObjType = {
"return-code",
NULL,
NULL,
NULL,
JIM_TYPE_NONE,
};
const char *Jim_ReturnCode(int code)
{
if (code < 0 || code >= (int)jimReturnCodesSize) {
return "?";
}
else {
return jimReturnCodes[code];
}
}
static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
{
int returnCode;
jim_wide wideValue;
if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
returnCode = (int)wideValue;
|
| ︙ | ︙ | |||
12150 12151 12152 12153 12154 12155 12156 |
static Jim_Obj *ExprPop(struct JimExprState *e)
{
return e->stack[--e->stacklen];
}
static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e)
{
| | < < < < > < < < < < > > > < < | < | 12386 12387 12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403 12404 12405 12406 12407 12408 12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 12423 12424 12425 12426 12427 12428 12429 12430 12431 12432 12433 12434 12435 12436 12437 12438 12439 12440 12441 12442 12443 12444 12445 12446 12447 12448 12449 12450 12451 12452 |
static Jim_Obj *ExprPop(struct JimExprState *e)
{
return e->stack[--e->stacklen];
}
static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e)
{
int intresult = 1;
int rc = JIM_OK;
Jim_Obj *A = ExprPop(e);
double dA, dC = 0;
jim_wide wA, wC = 0;
if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
switch (e->opcode) {
case JIM_EXPROP_FUNC_INT:
case JIM_EXPROP_FUNC_ROUND:
case JIM_EXPROP_UNARYPLUS:
wC = wA;
break;
case JIM_EXPROP_FUNC_DOUBLE:
dC = wA;
intresult = 0;
break;
case JIM_EXPROP_FUNC_ABS:
wC = wA >= 0 ? wA : -wA;
break;
case JIM_EXPROP_UNARYMINUS:
wC = -wA;
break;
case JIM_EXPROP_NOT:
wC = !wA;
break;
default:
abort();
}
}
else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
switch (e->opcode) {
case JIM_EXPROP_FUNC_INT:
wC = dA;
break;
case JIM_EXPROP_FUNC_ROUND:
wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
break;
case JIM_EXPROP_FUNC_DOUBLE:
case JIM_EXPROP_UNARYPLUS:
dC = dA;
intresult = 0;
break;
case JIM_EXPROP_FUNC_ABS:
dC = dA >= 0 ? dA : -dA;
intresult = 0;
break;
case JIM_EXPROP_UNARYMINUS:
dC = -dA;
intresult = 0;
break;
case JIM_EXPROP_NOT:
wC = !dA;
break;
default:
abort();
}
}
if (rc == JIM_OK) {
|
| ︙ | ︙ | |||
12425 12426 12427 12428 12429 12430 12431 |
return rc;
}
static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e)
{
| | < < | 12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667 12668 12669 12670 12671 12672 12673 12674 12675 12676 12677 12678 12679 12680 |
return rc;
}
static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e)
{
int intresult = 1;
int rc = JIM_OK;
double dA, dB, dC = 0;
jim_wide wA, wB, wC = 0;
Jim_Obj *B = ExprPop(e);
Jim_Obj *A = ExprPop(e);
if ((A->typePtr != &doubleObjType || A->bytes) &&
(B->typePtr != &doubleObjType || B->bytes) &&
JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
switch (e->opcode) {
case JIM_EXPROP_POW:
case JIM_EXPROP_FUNC_POW:
wC = JimPowWide(wA, wB);
break;
case JIM_EXPROP_ADD:
wC = wA + wB;
|
| ︙ | ︙ | |||
12494 12495 12496 12497 12498 12499 12500 12501 12502 12503 12504 12505 12506 12507 |
wC = wA != wB;
break;
default:
abort();
}
}
else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
switch (e->opcode) {
case JIM_EXPROP_POW:
case JIM_EXPROP_FUNC_POW:
#ifdef JIM_MATH_FUNCTIONS
dC = pow(dA, dB);
#else
Jim_SetResultString(interp, "unsupported", -1);
| > | 12720 12721 12722 12723 12724 12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 |
wC = wA != wB;
break;
default:
abort();
}
}
else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
intresult = 0;
switch (e->opcode) {
case JIM_EXPROP_POW:
case JIM_EXPROP_FUNC_POW:
#ifdef JIM_MATH_FUNCTIONS
dC = pow(dA, dB);
#else
Jim_SetResultString(interp, "unsupported", -1);
|
| ︙ | ︙ | |||
12559 12560 12561 12562 12563 12564 12565 |
}
else {
int i = Jim_StringCompareObj(interp, A, B, 0);
| < < | 12786 12787 12788 12789 12790 12791 12792 12793 12794 12795 12796 12797 12798 12799 |
}
else {
int i = Jim_StringCompareObj(interp, A, B, 0);
switch (e->opcode) {
case JIM_EXPROP_LT:
wC = i < 0;
break;
case JIM_EXPROP_GT:
wC = i > 0;
break;
|
| ︙ | ︙ | |||
12608 12609 12610 12611 12612 12613 12614 |
static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
{
int listlen;
int i;
listlen = Jim_ListLength(interp, listObjPtr);
for (i = 0; i < listlen; i++) {
| < < < < | | < < < | | | < < < < | 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 |
static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
{
int listlen;
int i;
listlen = Jim_ListLength(interp, listObjPtr);
for (i = 0; i < listlen; i++) {
if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) {
return 1;
}
}
return 0;
}
static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprState *e)
{
Jim_Obj *B = ExprPop(e);
Jim_Obj *A = ExprPop(e);
jim_wide wC;
switch (e->opcode) {
case JIM_EXPROP_STREQ:
case JIM_EXPROP_STRNE:
wC = Jim_StringEqObj(A, B);
if (e->opcode == JIM_EXPROP_STRNE) {
wC = !wC;
}
break;
case JIM_EXPROP_STRIN:
wC = JimSearchList(interp, B, A);
break;
case JIM_EXPROP_STRNI:
wC = !JimSearchList(interp, B, A);
break;
default:
|
| ︙ | ︙ | |||
12816 12817 12818 12819 12820 12821 12822 |
{
LAZY_NONE,
LAZY_OP,
LAZY_LEFT,
LAZY_RIGHT
};
| > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > | < | < | 13030 13031 13032 13033 13034 13035 13036 13037 13038 13039 13040 13041 13042 13043 13044 13045 13046 13047 13048 13049 13050 13051 13052 13053 13054 13055 13056 13057 13058 13059 13060 13061 13062 13063 13064 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094 13095 13096 13097 13098 13099 13100 13101 13102 13103 13104 13105 13106 13107 13108 13109 13110 13111 13112 13113 13114 13115 13116 13117 13118 13119 13120 13121 13122 13123 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133 13134 13135 13136 13137 13138 13139 13140 13141 13142 13143 13144 13145 13146 13147 13148 13149 13150 13151 13152 13153 13154 13155 13156 13157 13158 13159 13160 13161 13162 13163 13164 13165 13166 13167 |
{
LAZY_NONE,
LAZY_OP,
LAZY_LEFT,
LAZY_RIGHT
};
#define OPRINIT(N, P, A, F) {N, F, P, A, LAZY_NONE, sizeof(N) - 1}
#define OPRINIT_LAZY(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1}
static const struct Jim_ExprOperator Jim_ExprOperators[] = {
OPRINIT("*", 110, 2, JimExprOpBin),
OPRINIT("/", 110, 2, JimExprOpBin),
OPRINIT("%", 110, 2, JimExprOpIntBin),
OPRINIT("-", 100, 2, JimExprOpBin),
OPRINIT("+", 100, 2, JimExprOpBin),
OPRINIT("<<", 90, 2, JimExprOpIntBin),
OPRINIT(">>", 90, 2, JimExprOpIntBin),
OPRINIT("<<<", 90, 2, JimExprOpIntBin),
OPRINIT(">>>", 90, 2, JimExprOpIntBin),
OPRINIT("<", 80, 2, JimExprOpBin),
OPRINIT(">", 80, 2, JimExprOpBin),
OPRINIT("<=", 80, 2, JimExprOpBin),
OPRINIT(">=", 80, 2, JimExprOpBin),
OPRINIT("==", 70, 2, JimExprOpBin),
OPRINIT("!=", 70, 2, JimExprOpBin),
OPRINIT("&", 50, 2, JimExprOpIntBin),
OPRINIT("^", 49, 2, JimExprOpIntBin),
OPRINIT("|", 48, 2, JimExprOpIntBin),
OPRINIT_LAZY("&&", 10, 2, NULL, LAZY_OP),
OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT),
OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT),
OPRINIT_LAZY("||", 9, 2, NULL, LAZY_OP),
OPRINIT_LAZY(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT),
OPRINIT_LAZY(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT),
OPRINIT_LAZY("?", 5, 2, JimExprOpNull, LAZY_OP),
OPRINIT_LAZY(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT),
OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
OPRINIT_LAZY(":", 5, 2, JimExprOpNull, LAZY_OP),
OPRINIT_LAZY(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT),
OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
OPRINIT("**", 250, 2, JimExprOpBin),
OPRINIT("eq", 60, 2, JimExprOpStrBin),
OPRINIT("ne", 60, 2, JimExprOpStrBin),
OPRINIT("in", 55, 2, JimExprOpStrBin),
OPRINIT("ni", 55, 2, JimExprOpStrBin),
OPRINIT("!", 150, 1, JimExprOpNumUnary),
OPRINIT("~", 150, 1, JimExprOpIntUnary),
OPRINIT(NULL, 150, 1, JimExprOpNumUnary),
OPRINIT(NULL, 150, 1, JimExprOpNumUnary),
OPRINIT("int", 200, 1, JimExprOpNumUnary),
OPRINIT("abs", 200, 1, JimExprOpNumUnary),
OPRINIT("double", 200, 1, JimExprOpNumUnary),
OPRINIT("round", 200, 1, JimExprOpNumUnary),
OPRINIT("rand", 200, 0, JimExprOpNone),
OPRINIT("srand", 200, 1, JimExprOpIntUnary),
#ifdef JIM_MATH_FUNCTIONS
OPRINIT("sin", 200, 1, JimExprOpDoubleUnary),
OPRINIT("cos", 200, 1, JimExprOpDoubleUnary),
OPRINIT("tan", 200, 1, JimExprOpDoubleUnary),
OPRINIT("asin", 200, 1, JimExprOpDoubleUnary),
OPRINIT("acos", 200, 1, JimExprOpDoubleUnary),
OPRINIT("atan", 200, 1, JimExprOpDoubleUnary),
OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary),
OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary),
OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary),
OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary),
OPRINIT("floor", 200, 1, JimExprOpDoubleUnary),
OPRINIT("exp", 200, 1, JimExprOpDoubleUnary),
OPRINIT("log", 200, 1, JimExprOpDoubleUnary),
OPRINIT("log10", 200, 1, JimExprOpDoubleUnary),
OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary),
OPRINIT("pow", 200, 2, JimExprOpBin),
#endif
};
#undef OPRINIT
#undef OPRINIT_LAZY
#define JIM_EXPR_OPERATORS_NUM \
(sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
static int JimParseExpression(struct JimParserCtx *pc)
{
while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
if (*pc->p == '\n') {
pc->linenr++;
}
pc->p++;
pc->len--;
}
pc->tline = pc->linenr;
pc->tstart = pc->p;
if (pc->len == 0) {
pc->tend = pc->p;
pc->tt = JIM_TT_EOL;
pc->eof = 1;
return JIM_OK;
}
switch (*(pc->p)) {
case '(':
pc->tt = JIM_TT_SUBEXPR_START;
goto singlechar;
case ')':
pc->tt = JIM_TT_SUBEXPR_END;
goto singlechar;
case ',':
pc->tt = JIM_TT_SUBEXPR_COMMA;
singlechar:
pc->tend = pc->p;
pc->p++;
pc->len--;
break;
case '[':
return JimParseCmd(pc);
case '$':
if (JimParseVar(pc) == JIM_ERR)
|
| ︙ | ︙ | |||
12985 12986 12987 12988 12989 12990 12991 |
break;
}
return JIM_OK;
}
static int JimParseExprNumber(struct JimParserCtx *pc)
{
| | < < < > < < < < < < | | < < < < < | < | < < < < | < < | < < < < < < < < < < < < < < < | < < > | | | | | < < | | | | 13203 13204 13205 13206 13207 13208 13209 13210 13211 13212 13213 13214 13215 13216 13217 13218 13219 13220 13221 13222 13223 13224 13225 13226 13227 13228 13229 13230 13231 13232 13233 13234 13235 13236 13237 13238 13239 13240 13241 13242 13243 13244 13245 13246 13247 13248 13249 13250 |
break;
}
return JIM_OK;
}
static int JimParseExprNumber(struct JimParserCtx *pc)
{
char *end;
pc->tt = JIM_TT_EXPR_INT;
jim_strtoull(pc->p, (char **)&pc->p);
if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
if (strtod(pc->tstart, &end)) { }
if (end == pc->tstart)
return JIM_ERR;
if (end > pc->p) {
pc->tt = JIM_TT_EXPR_DOUBLE;
pc->p = end;
}
}
pc->tend = pc->p - 1;
pc->len -= (pc->p - pc->tstart);
return JIM_OK;
}
static int JimParseExprIrrational(struct JimParserCtx *pc)
{
const char *irrationals[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
int i;
for (i = 0; irrationals[i]; i++) {
const char *irr = irrationals[i];
if (strncmp(irr, pc->p, 3) == 0) {
pc->p += 3;
pc->len -= 3;
pc->tend = pc->p - 1;
pc->tt = JIM_TT_EXPR_DOUBLE;
return JIM_OK;
}
}
return JIM_ERR;
}
|
| ︙ | ︙ | |||
13100 13101 13102 13103 13104 13105 13106 |
len--;
p++;
}
if (*p != '(') {
return JIM_ERR;
}
}
| < < | 13280 13281 13282 13283 13284 13285 13286 13287 13288 13289 13290 13291 13292 13293 13294 13295 13296 |
len--;
p++;
}
if (*p != '(') {
return JIM_ERR;
}
}
pc->tend = pc->p + bestLen - 1;
pc->p += bestLen;
pc->len -= bestLen;
pc->tt = bestIdx;
return JIM_OK;
}
static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
{
|
| ︙ | ︙ | |||
13606 13607 13608 13609 13610 13611 13612 |
ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
parser.tline);
}
#ifdef DEBUG_SHOW_EXPR_TOKENS
{
int i;
| | > > > > > > | 13784 13785 13786 13787 13788 13789 13790 13791 13792 13793 13794 13795 13796 13797 13798 13799 13800 13801 13802 13803 13804 13805 13806 13807 13808 13809 13810 |
ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
parser.tline);
}
#ifdef DEBUG_SHOW_EXPR_TOKENS
{
int i;
printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj));
for (i = 0; i < tokenlist.count; i++) {
printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type),
tokenlist.list[i].len, tokenlist.list[i].token);
}
}
#endif
if (JimParseCheckMissing(interp, parser.missing.ch) == JIM_ERR) {
ScriptTokenListFree(&tokenlist);
Jim_DecrRefCount(interp, fileNameObj);
return JIM_ERR;
}
expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj);
ScriptTokenListFree(&tokenlist);
|
| ︙ | ︙ | |||
13663 13664 13665 13666 13667 13668 13669 13670 13671 13672 13673 13674 13675 13676 |
if (objPtr->typePtr != &exprObjType) {
if (SetExprFromAny(interp, objPtr) != JIM_OK) {
return NULL;
}
}
return (ExprByteCode *) Jim_GetIntRepPtr(objPtr);
}
#define JIM_EE_STATICSTACK_LEN 10
int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr)
{
ExprByteCode *expr;
Jim_Obj *staticStack[JIM_EE_STATICSTACK_LEN];
| > > > > > > > > > > > > > > | 13847 13848 13849 13850 13851 13852 13853 13854 13855 13856 13857 13858 13859 13860 13861 13862 13863 13864 13865 13866 13867 13868 13869 13870 13871 13872 13873 13874 |
if (objPtr->typePtr != &exprObjType) {
if (SetExprFromAny(interp, objPtr) != JIM_OK) {
return NULL;
}
}
return (ExprByteCode *) Jim_GetIntRepPtr(objPtr);
}
#ifdef JIM_OPTIMIZATION
static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, const ScriptToken *token)
{
if (token->type == JIM_TT_EXPR_INT)
return token->objPtr;
else if (token->type == JIM_TT_VAR)
return Jim_GetVariable(interp, token->objPtr, JIM_NONE);
else if (token->type == JIM_TT_DICTSUGAR)
return JimExpandDictSugar(interp, token->objPtr);
else
return NULL;
}
#endif
#define JIM_EE_STATICSTACK_LEN 10
int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr)
{
ExprByteCode *expr;
Jim_Obj *staticStack[JIM_EE_STATICSTACK_LEN];
|
| ︙ | ︙ | |||
13686 13687 13688 13689 13690 13691 13692 |
#ifdef JIM_OPTIMIZATION
{
Jim_Obj *objPtr;
switch (expr->len) {
case 1:
| | | | < < < < < | < | < | | < | < | | | | < < < < < < | | | < < < < < < < < < < < < < < | < | | | | | | | | | | | | | | | | | | | | | | < | | | | | < < < > | 13884 13885 13886 13887 13888 13889 13890 13891 13892 13893 13894 13895 13896 13897 13898 13899 13900 13901 13902 13903 13904 13905 13906 13907 13908 13909 13910 13911 13912 13913 13914 13915 13916 13917 13918 13919 13920 13921 13922 13923 13924 13925 13926 13927 13928 13929 13930 13931 13932 13933 13934 13935 13936 13937 13938 13939 13940 13941 13942 13943 13944 13945 13946 13947 13948 13949 13950 13951 13952 13953 13954 13955 13956 |
#ifdef JIM_OPTIMIZATION
{
Jim_Obj *objPtr;
switch (expr->len) {
case 1:
objPtr = JimExprIntValOrVar(interp, &expr->token[0]);
if (objPtr) {
Jim_IncrRefCount(objPtr);
*exprResultPtrPtr = objPtr;
return JIM_OK;
}
break;
case 2:
if (expr->token[1].type == JIM_EXPROP_NOT) {
objPtr = JimExprIntValOrVar(interp, &expr->token[0]);
if (objPtr && JimIsWide(objPtr)) {
*exprResultPtrPtr = JimWideValue(objPtr) ? interp->falseObj : interp->trueObj;
Jim_IncrRefCount(*exprResultPtrPtr);
return JIM_OK;
}
}
break;
case 3:
objPtr = JimExprIntValOrVar(interp, &expr->token[0]);
if (objPtr && JimIsWide(objPtr)) {
Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, &expr->token[1]);
if (objPtr2 && JimIsWide(objPtr2)) {
jim_wide wideValueA = JimWideValue(objPtr);
jim_wide wideValueB = JimWideValue(objPtr2);
int cmpRes;
switch (expr->token[2].type) {
case JIM_EXPROP_LT:
cmpRes = wideValueA < wideValueB;
break;
case JIM_EXPROP_LTE:
cmpRes = wideValueA <= wideValueB;
break;
case JIM_EXPROP_GT:
cmpRes = wideValueA > wideValueB;
break;
case JIM_EXPROP_GTE:
cmpRes = wideValueA >= wideValueB;
break;
case JIM_EXPROP_NUMEQ:
cmpRes = wideValueA == wideValueB;
break;
case JIM_EXPROP_NUMNE:
cmpRes = wideValueA != wideValueB;
break;
default:
goto noopt;
}
*exprResultPtrPtr = cmpRes ? interp->trueObj : interp->falseObj;
Jim_IncrRefCount(*exprResultPtrPtr);
return JIM_OK;
}
}
break;
}
}
noopt:
#endif
expr->inUse++;
if (expr->len > JIM_EE_STATICSTACK_LEN)
|
| ︙ | ︙ | |||
13950 13951 13952 13953 13954 13955 13956 |
JIM_NOTUSED(interp);
memcpy(newVec, srcPtr->internalRep.ptr, size);
dupPtr->internalRep.ptr = newVec;
dupPtr->typePtr = &scanFmtStringObjType;
}
| | | < < < | 14115 14116 14117 14118 14119 14120 14121 14122 14123 14124 14125 14126 14127 14128 14129 14130 14131 |
JIM_NOTUSED(interp);
memcpy(newVec, srcPtr->internalRep.ptr, size);
dupPtr->internalRep.ptr = newVec;
dupPtr->typePtr = &scanFmtStringObjType;
}
static void UpdateStringOfScanFmt(Jim_Obj *objPtr)
{
JimSetStringBytes(objPtr, ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep);
}
static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
{
ScanFmtStringObj *fmtObj;
char *buffer;
|
| ︙ | ︙ | |||
14169 14170 14171 14172 14173 14174 14175 |
size_t anchor = pos;
int i;
Jim_Obj *tmpObj = NULL;
*valObjPtr = 0;
if (descr->prefix) {
| < | 14331 14332 14333 14334 14335 14336 14337 14338 14339 14340 14341 14342 14343 14344 |
size_t anchor = pos;
int i;
Jim_Obj *tmpObj = NULL;
*valObjPtr = 0;
if (descr->prefix) {
for (i = 0; pos < strLen && descr->prefix[i]; ++i) {
if (isspace(UCHAR(descr->prefix[i])))
while (pos < strLen && isspace(UCHAR(str[pos])))
++pos;
else if (descr->prefix[i] != str[pos])
break;
|
| ︙ | ︙ | |||
14510 14511 14512 14513 14514 14515 14516 |
return retcode;
}
static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
{
int retcode;
| | > > > > > > > > > > > > > > > > | | | > > > | > < < > > > | 14671 14672 14673 14674 14675 14676 14677 14678 14679 14680 14681 14682 14683 14684 14685 14686 14687 14688 14689 14690 14691 14692 14693 14694 14695 14696 14697 14698 14699 14700 14701 14702 14703 14704 14705 14706 14707 14708 14709 14710 14711 14712 14713 14714 14715 14716 14717 14718 14719 14720 14721 14722 14723 14724 14725 14726 14727 14728 14729 |
return retcode;
}
static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
{
int retcode;
Jim_Cmd *cmdPtr;
#if 0
printf("invoke");
int j;
for (j = 0; j < objc; j++) {
printf(" '%s'", Jim_String(objv[j]));
}
printf("\n");
#endif
if (interp->framePtr->tailcallCmd) {
cmdPtr = interp->framePtr->tailcallCmd;
interp->framePtr->tailcallCmd = NULL;
}
else {
cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
if (cmdPtr == NULL) {
return JimUnknown(interp, objc, objv);
}
JimIncrCmdRefCount(cmdPtr);
}
if (interp->evalDepth == interp->maxEvalDepth) {
Jim_SetResultString(interp, "Infinite eval recursion", -1);
retcode = JIM_ERR;
goto out;
}
interp->evalDepth++;
Jim_SetEmptyResult(interp);
if (cmdPtr->isproc) {
retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
}
else {
interp->cmdPrivData = cmdPtr->u.native.privData;
retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
}
interp->evalDepth--;
out:
JimDecrCmdRefCount(interp, cmdPtr);
return retcode;
}
int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
{
int i, retcode;
|
| ︙ | ︙ | |||
14715 14716 14717 14718 14719 14720 14721 14722 14723 14724 14725 14726 14727 14728 |
&& token[2].type == JIM_TT_VAR) {
objPtr->typePtr = &interpolatedObjType;
objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
Jim_IncrRefCount(intv[2]);
}
s = objPtr->bytes = Jim_Alloc(totlen + 1);
objPtr->length = totlen;
for (i = 0; i < tokens; i++) {
if (intv[i]) {
memcpy(s, intv[i]->bytes, intv[i]->length);
s += intv[i]->length;
| > > > > > | 14897 14898 14899 14900 14901 14902 14903 14904 14905 14906 14907 14908 14909 14910 14911 14912 14913 14914 14915 |
&& token[2].type == JIM_TT_VAR) {
objPtr->typePtr = &interpolatedObjType;
objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
Jim_IncrRefCount(intv[2]);
}
else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber);
}
s = objPtr->bytes = Jim_Alloc(totlen + 1);
objPtr->length = totlen;
for (i = 0; i < tokens; i++) {
if (intv[i]) {
memcpy(s, intv[i]->bytes, intv[i]->length);
s += intv[i]->length;
|
| ︙ | ︙ | |||
14770 14771 14772 14773 14774 14775 14776 14777 14778 14779 14780 14781 14782 14783 |
if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
return JimEvalObjList(interp, scriptObjPtr);
}
Jim_IncrRefCount(scriptObjPtr);
script = Jim_GetScript(interp, scriptObjPtr);
Jim_SetEmptyResult(interp);
token = script->token;
#ifdef JIM_OPTIMIZATION
if (script->len == 0) {
| > > > > | 14957 14958 14959 14960 14961 14962 14963 14964 14965 14966 14967 14968 14969 14970 14971 14972 14973 14974 |
if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
return JimEvalObjList(interp, scriptObjPtr);
}
Jim_IncrRefCount(scriptObjPtr);
script = Jim_GetScript(interp, scriptObjPtr);
if (script == NULL) {
Jim_DecrRefCount(interp, scriptObjPtr);
return JIM_ERR;
}
Jim_SetEmptyResult(interp);
token = script->token;
#ifdef JIM_OPTIMIZATION
if (script->len == 0) {
|
| ︙ | ︙ | |||
15044 15045 15046 15047 15048 15049 15050 |
else {
retcode = Jim_EvalObj(interp, scriptObj);
}
interp->framePtr = interp->framePtr->parent;
| < | < < < < < | 15235 15236 15237 15238 15239 15240 15241 15242 15243 15244 15245 15246 15247 15248 15249 15250 15251 15252 15253 15254 15255 15256 15257 15258 |
else {
retcode = Jim_EvalObj(interp, scriptObj);
}
interp->framePtr = interp->framePtr->parent;
JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
return retcode;
}
#endif
static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv)
{
Jim_CallFrame *callFramePtr;
int i, d, retcode, optargs;
ScriptObj *script;
if (argc - 1 < cmd->u.proc.reqArity ||
(cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
JimSetProcWrongArgs(interp, argv[0], cmd);
return JIM_ERR;
|
| ︙ | ︙ | |||
15143 15144 15145 15146 15147 15148 15149 |
}
}
retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
badargset:
| | < < < < | | > | | | > > > | | > > | | < | | > | | > | | > | > < < < | 15328 15329 15330 15331 15332 15333 15334 15335 15336 15337 15338 15339 15340 15341 15342 15343 15344 15345 15346 15347 15348 15349 15350 15351 15352 15353 15354 15355 15356 15357 15358 15359 15360 15361 15362 15363 15364 15365 15366 15367 15368 15369 15370 15371 15372 15373 15374 15375 15376 15377 15378 15379 15380 15381 15382 15383 15384 15385 15386 15387 15388 |
}
}
retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
badargset:
interp->framePtr = interp->framePtr->parent;
JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
if (interp->framePtr->tailcallObj) {
if (interp->framePtr->tailcall++ == 0) {
do {
Jim_Obj *tailcallObj = interp->framePtr->tailcallObj;
interp->framePtr->tailcallObj = NULL;
if (retcode == JIM_EVAL) {
retcode = Jim_EvalObjList(interp, tailcallObj);
if (retcode == JIM_RETURN) {
interp->returnLevel++;
}
}
Jim_DecrRefCount(interp, tailcallObj);
} while (interp->framePtr->tailcallObj);
if (interp->framePtr->tailcallCmd) {
JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
interp->framePtr->tailcallCmd = NULL;
}
}
interp->framePtr->tailcall--;
}
if (retcode == JIM_RETURN) {
if (--interp->returnLevel <= 0) {
retcode = interp->returnCode;
interp->returnCode = JIM_OK;
interp->returnLevel = 0;
}
}
else if (retcode == JIM_ERR) {
interp->addStackTrace++;
Jim_DecrRefCount(interp, interp->errorProc);
interp->errorProc = argv[0];
Jim_IncrRefCount(interp->errorProc);
}
return retcode;
}
int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
{
int retval;
Jim_Obj *scriptObjPtr;
|
| ︙ | ︙ | |||
15259 15260 15261 15262 15263 15264 15265 |
FILE *fp;
char *buf;
Jim_Obj *scriptObjPtr;
Jim_Obj *prevScriptObj;
struct stat sb;
int retcode;
int readlen;
| < | 15446 15447 15448 15449 15450 15451 15452 15453 15454 15455 15456 15457 15458 15459 |
FILE *fp;
char *buf;
Jim_Obj *scriptObjPtr;
Jim_Obj *prevScriptObj;
struct stat sb;
int retcode;
int readlen;
if (stat(filename, &sb) != 0 || (fp = fopen(filename, "rt")) == NULL) {
Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
return JIM_ERR;
}
if (sb.st_size == 0) {
fclose(fp);
|
| ︙ | ︙ | |||
15286 15287 15288 15289 15290 15291 15292 |
buf[readlen] = 0;
scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1);
Jim_IncrRefCount(scriptObjPtr);
| | < < | < < < < < < < < < < < < | < < < < | 15472 15473 15474 15475 15476 15477 15478 15479 15480 15481 15482 15483 15484 15485 15486 15487 15488 |
buf[readlen] = 0;
scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1);
Jim_IncrRefCount(scriptObjPtr);
if (Jim_GetScript(interp, scriptObjPtr) == NULL) {
JimAddErrorToStack(interp, JIM_ERR, (ScriptObj *)Jim_GetIntRepPtr(scriptObjPtr));
Jim_DecrRefCount(interp, scriptObjPtr);
return JIM_ERR;
}
prevScriptObj = interp->currentScriptObj;
interp->currentScriptObj = scriptObjPtr;
|
| ︙ | ︙ | |||
15473 15474 15475 15476 15477 15478 15479 |
Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
Jim_DecrRefCount(interp, objPtr);
}
typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
Jim_HashEntry *he, int type);
| | | 15641 15642 15643 15644 15645 15646 15647 15648 15649 15650 15651 15652 15653 15654 15655 |
Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
Jim_DecrRefCount(interp, objPtr);
}
typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
Jim_HashEntry *he, int type);
#define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
JimHashtableIteratorCallbackType *callback, int type)
{
Jim_HashEntry *he;
Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
|
| ︙ | ︙ | |||
15508 15509 15510 15511 15512 15513 15514 |
#define JIM_CMDLIST_COMMANDS 0
#define JIM_CMDLIST_PROCS 1
#define JIM_CMDLIST_CHANNELS 2
static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
Jim_HashEntry *he, int type)
{
| | | 15676 15677 15678 15679 15680 15681 15682 15683 15684 15685 15686 15687 15688 15689 15690 |
#define JIM_CMDLIST_COMMANDS 0
#define JIM_CMDLIST_PROCS 1
#define JIM_CMDLIST_CHANNELS 2
static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
Jim_HashEntry *he, int type)
{
Jim_Cmd *cmdPtr = Jim_GetHashEntryVal(he);
Jim_Obj *objPtr;
if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
return;
}
|
| ︙ | ︙ | |||
15541 15542 15543 15544 15545 15546 15547 |
#define JIM_VARLIST_VARS 2
#define JIM_VARLIST_VALUES 0x1000
static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
Jim_HashEntry *he, int type)
{
| | | 15709 15710 15711 15712 15713 15714 15715 15716 15717 15718 15719 15720 15721 15722 15723 |
#define JIM_VARLIST_VARS 2
#define JIM_VARLIST_VALUES 0x1000
static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
Jim_HashEntry *he, int type)
{
Jim_Var *varPtr = Jim_GetHashEntryVal(he);
if (type != JIM_VARLIST_LOCALS || varPtr->linkFramePtr == NULL) {
Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1));
if (type & JIM_VARLIST_VALUES) {
Jim_ListAppendElement(interp, listObjPtr, varPtr->objPtr);
}
}
|
| ︙ | ︙ | |||
15863 15864 15865 15866 15867 15868 15869 |
int cmpOffset;
expr = JimGetExpression(interp, argv[2]);
incrScript = Jim_GetScript(interp, argv[3]);
| | | 16031 16032 16033 16034 16035 16036 16037 16038 16039 16040 16041 16042 16043 16044 16045 |
int cmpOffset;
expr = JimGetExpression(interp, argv[2]);
incrScript = Jim_GetScript(interp, argv[3]);
if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) {
goto evalstart;
}
if (incrScript->token[1].type != JIM_TT_ESC ||
expr->token[0].type != JIM_TT_VAR ||
(expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) {
goto evalstart;
|
| ︙ | ︙ | |||
16086 16087 16088 16089 16090 16091 16092 |
{
return iter->idx >= Jim_ListLength(interp, iter->objPtr);
}
static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
{
| | | 16254 16255 16256 16257 16258 16259 16260 16261 16262 16263 16264 16265 16266 16267 16268 |
{
return iter->idx >= Jim_ListLength(interp, iter->objPtr);
}
static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
{
int result = JIM_OK;
int i, numargs;
Jim_ListIter twoiters[2];
Jim_ListIter *iters;
Jim_Obj *script;
Jim_Obj *resultObj;
if (argc < 4 || argc % 2 != 0) {
|
| ︙ | ︙ | |||
16109 16110 16111 16112 16113 16114 16115 |
}
else {
iters = Jim_Alloc(numargs * sizeof(*iters));
}
for (i = 0; i < numargs; i++) {
JimListIterInit(&iters[i], argv[i + 1]);
if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) {
| < | > > > > | 16277 16278 16279 16280 16281 16282 16283 16284 16285 16286 16287 16288 16289 16290 16291 16292 16293 16294 16295 16296 |
}
else {
iters = Jim_Alloc(numargs * sizeof(*iters));
}
for (i = 0; i < numargs; i++) {
JimListIterInit(&iters[i], argv[i + 1]);
if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) {
result = JIM_ERR;
}
}
if (result != JIM_OK) {
Jim_SetResultString(interp, "foreach varlist is empty", -1);
return result;
}
if (doMap) {
resultObj = Jim_NewListObj(interp, NULL, 0);
}
else {
resultObj = interp->emptyObj;
|
| ︙ | ︙ | |||
16428 16429 16430 16431 16432 16433 16434 |
static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *objPtr, *listObjPtr;
int i;
int idx;
| | | | 16599 16600 16601 16602 16603 16604 16605 16606 16607 16608 16609 16610 16611 16612 16613 16614 |
static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *objPtr, *listObjPtr;
int i;
int idx;
if (argc < 2) {
Jim_WrongNumArgs(interp, 1, argv, "list ?index ...?");
return JIM_ERR;
}
objPtr = argv[1];
Jim_IncrRefCount(objPtr);
for (i = 2; i < argc; i++) {
listObjPtr = objPtr;
if (Jim_GetIndex(interp, argv[i], &idx) != JIM_OK) {
|
| ︙ | ︙ | |||
16545 16546 16547 16548 16549 16550 16551 |
}
if (commandObj) {
Jim_IncrRefCount(commandObj);
}
listlen = Jim_ListLength(interp, argv[0]);
for (i = 0; i < listlen; i++) {
| < > < | 16716 16717 16718 16719 16720 16721 16722 16723 16724 16725 16726 16727 16728 16729 16730 16731 16732 |
}
if (commandObj) {
Jim_IncrRefCount(commandObj);
}
listlen = Jim_ListLength(interp, argv[0]);
for (i = 0; i < listlen; i++) {
int eq = 0;
Jim_Obj *objPtr = Jim_ListGetIndex(interp, argv[0], i);
switch (opt_match) {
case OPT_EXACT:
eq = Jim_StringCompareObj(interp, argv[1], objPtr, opt_nocase) == 0;
break;
case OPT_GLOB:
eq = Jim_StringMatchObj(interp, argv[1], objPtr, opt_nocase);
|
| ︙ | ︙ | |||
16742 16743 16744 16745 16746 16747 16748 16749 16750 16751 16752 16753 |
static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
if (argc < 3) {
Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
return JIM_ERR;
}
else if (argc == 3) {
if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
return JIM_ERR;
Jim_SetResult(interp, argv[2]);
return JIM_OK;
}
| > | < < < | | > | > > > > > > | 16912 16913 16914 16915 16916 16917 16918 16919 16920 16921 16922 16923 16924 16925 16926 16927 16928 16929 16930 16931 16932 16933 16934 16935 16936 16937 16938 16939 16940 16941 16942 16943 16944 16945 16946 16947 16948 16949 16950 16951 16952 16953 16954 16955 16956 16957 16958 16959 16960 16961 16962 16963 16964 16965 16966 16967 16968 16969 16970 16971 16972 16973 16974 16975 16976 16977 16978 16979 16980 16981 16982 16983 16984 16985 16986 16987 16988 |
static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
if (argc < 3) {
Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
return JIM_ERR;
}
else if (argc == 3) {
if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
return JIM_ERR;
Jim_SetResult(interp, argv[2]);
return JIM_OK;
}
return Jim_ListSetIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]);
}
static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
{
static const char * const options[] = {
"-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique", NULL
};
enum
{ OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE };
Jim_Obj *resObj;
int i;
int retCode;
struct lsort_info info;
if (argc < 2) {
Jim_WrongNumArgs(interp, 1, argv, "?options? list");
return JIM_ERR;
}
info.type = JIM_LSORT_ASCII;
info.order = 1;
info.indexed = 0;
info.unique = 0;
info.command = NULL;
info.interp = interp;
for (i = 1; i < (argc - 1); i++) {
int option;
if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG)
!= JIM_OK)
return JIM_ERR;
switch (option) {
case OPT_ASCII:
info.type = JIM_LSORT_ASCII;
break;
case OPT_NOCASE:
info.type = JIM_LSORT_NOCASE;
break;
case OPT_INTEGER:
info.type = JIM_LSORT_INTEGER;
break;
case OPT_REAL:
info.type = JIM_LSORT_REAL;
break;
case OPT_INCREASING:
info.order = 1;
break;
case OPT_DECREASING:
info.order = -1;
break;
case OPT_UNIQUE:
info.unique = 1;
break;
case OPT_COMMAND:
if (i >= (argc - 2)) {
Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1);
return JIM_ERR;
}
info.type = JIM_LSORT_COMMAND;
info.command = argv[i + 1];
|
| ︙ | ︙ | |||
16913 16914 16915 16916 16917 16918 16919 |
static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
if (argc >= 2) {
int retcode;
Jim_CallFrame *savedCallFrame, *targetCallFrame;
| | | < | > > > < < | < > | 17088 17089 17090 17091 17092 17093 17094 17095 17096 17097 17098 17099 17100 17101 17102 17103 17104 17105 17106 17107 17108 17109 17110 17111 17112 17113 17114 17115 17116 17117 17118 17119 17120 17121 17122 17123 17124 17125 17126 17127 17128 17129 17130 17131 17132 17133 17134 17135 17136 |
static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
if (argc >= 2) {
int retcode;
Jim_CallFrame *savedCallFrame, *targetCallFrame;
int savedTailcall;
const char *str;
savedCallFrame = interp->framePtr;
str = Jim_String(argv[1]);
if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
argc--;
argv++;
}
else {
targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
}
if (targetCallFrame == NULL) {
return JIM_ERR;
}
if (argc < 2) {
Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?");
return JIM_ERR;
}
interp->framePtr = targetCallFrame;
savedTailcall = interp->framePtr->tailcall;
interp->framePtr->tailcall = 0;
if (argc == 2) {
retcode = Jim_EvalObj(interp, argv[1]);
}
else {
retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
}
interp->framePtr->tailcall = savedTailcall;
interp->framePtr = savedCallFrame;
return retcode;
}
else {
Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
return JIM_ERR;
}
|
| ︙ | ︙ | |||
17062 17063 17064 17065 17066 17067 17068 |
}
return JIM_RETURN;
}
static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
| > > > > > > > > > > > > > > > > > > > > > > | > > > | > > | 17237 17238 17239 17240 17241 17242 17243 17244 17245 17246 17247 17248 17249 17250 17251 17252 17253 17254 17255 17256 17257 17258 17259 17260 17261 17262 17263 17264 17265 17266 17267 17268 17269 17270 17271 17272 17273 17274 17275 17276 17277 17278 17279 |
}
return JIM_RETURN;
}
static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
if (interp->framePtr->level == 0) {
Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1);
return JIM_ERR;
}
else if (argc >= 2) {
Jim_CallFrame *cf = interp->framePtr->parent;
Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
if (cmdPtr == NULL) {
return JIM_ERR;
}
JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd"));
JimIncrCmdRefCount(cmdPtr);
cf->tailcallCmd = cmdPtr;
JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj"));
cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1);
Jim_IncrRefCount(cf->tailcallObj);
return JIM_EVAL;
}
return JIM_OK;
}
static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *cmdList;
Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
|
| ︙ | ︙ | |||
17352 17353 17354 17355 17356 17357 17358 |
resultObjPtr = Jim_NewStringObj(interp, "", 0);
while (strLen) {
for (i = 0; i < numMaps; i += 2) {
Jim_Obj *objPtr;
const char *k;
int kl;
| | < | | 17554 17555 17556 17557 17558 17559 17560 17561 17562 17563 17564 17565 17566 17567 17568 17569 17570 17571 17572 17573 17574 17575 17576 17577 17578 17579 17580 |
resultObjPtr = Jim_NewStringObj(interp, "", 0);
while (strLen) {
for (i = 0; i < numMaps; i += 2) {
Jim_Obj *objPtr;
const char *k;
int kl;
objPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
k = Jim_String(objPtr);
kl = Jim_Utf8Length(interp, objPtr);
if (strLen >= kl && kl) {
int rc;
rc = JimStringCompareLen(str, k, kl, nocase);
if (rc == 0) {
if (noMatchStart) {
Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
noMatchStart = NULL;
}
Jim_AppendObj(interp, resultObjPtr, Jim_ListGetIndex(interp, mapListObjPtr, i + 1));
str += utf8_index(str, kl);
strLen -= kl;
break;
}
}
}
if (i == numMaps) {
|
| ︙ | ︙ | |||
17849 17850 17851 17852 17853 17854 17855 17856 17857 17858 17859 |
interp->signal_level += sig;
if (Jim_CheckSignal(interp)) {
exitCode = JIM_SIGNAL;
}
else {
exitCode = Jim_EvalObj(interp, argv[0]);
}
interp->signal_level -= sig;
| > > | | 18050 18051 18052 18053 18054 18055 18056 18057 18058 18059 18060 18061 18062 18063 18064 18065 18066 18067 18068 18069 18070 |
interp->signal_level += sig;
if (Jim_CheckSignal(interp)) {
exitCode = JIM_SIGNAL;
}
else {
exitCode = Jim_EvalObj(interp, argv[0]);
interp->errorFlag = 0;
}
interp->signal_level -= sig;
if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {
return exitCode;
}
if (sig && exitCode == JIM_SIGNAL) {
if (interp->signal_set_result) {
|
| ︙ | ︙ | |||
18007 18008 18009 18010 18011 18012 18013 |
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];
| | | 18210 18211 18212 18213 18214 18215 18216 18217 18218 18219 18220 18221 18222 18223 18224 |
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 = Jim_GetHashEntryVal(he);
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;
|
| ︙ | ︙ | |||
18041 18042 18043 18044 18045 18046 18047 |
typedef void JimDictMatchCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type);
static void JimDictMatchKeys(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type)
{
Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key);
if (type & JIM_DICTMATCH_VALUES) {
| | | 18244 18245 18246 18247 18248 18249 18250 18251 18252 18253 18254 18255 18256 18257 18258 |
typedef void JimDictMatchCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type);
static void JimDictMatchKeys(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type)
{
Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key);
if (type & JIM_DICTMATCH_VALUES) {
Jim_ListAppendElement(interp, listObjPtr, Jim_GetHashEntryVal(he));
}
}
static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
JimDictMatchCallbackType *callback, int type)
{
Jim_HashEntry *he;
|
| ︙ | ︙ | |||
18090 18091 18092 18093 18094 18095 18096 18097 18098 18099 18100 18101 18102 |
{
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
return -1;
}
return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
}
static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *objPtr;
int option;
static const char * const options[] = {
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > | | | | > | > | > > | > | > > > | | < < | < | < | < | < < | > | | < < | < < > | < < | > > > | > > > > > | 18293 18294 18295 18296 18297 18298 18299 18300 18301 18302 18303 18304 18305 18306 18307 18308 18309 18310 18311 18312 18313 18314 18315 18316 18317 18318 18319 18320 18321 18322 18323 18324 18325 18326 18327 18328 18329 18330 18331 18332 18333 18334 18335 18336 18337 18338 18339 18340 18341 18342 18343 18344 18345 18346 18347 18348 18349 18350 18351 18352 18353 18354 18355 18356 18357 18358 18359 18360 18361 18362 18363 18364 18365 18366 18367 18368 18369 18370 18371 18372 18373 18374 18375 18376 18377 18378 18379 18380 18381 18382 18383 18384 18385 18386 18387 18388 18389 18390 18391 18392 18393 18394 18395 18396 18397 18398 18399 18400 18401 18402 18403 18404 18405 18406 18407 18408 18409 18410 18411 18412 18413 18414 18415 18416 18417 18418 18419 18420 18421 18422 18423 18424 18425 18426 18427 18428 18429 18430 18431 18432 18433 18434 18435 18436 18437 18438 18439 18440 18441 18442 18443 18444 18445 18446 18447 18448 18449 18450 18451 18452 18453 18454 18455 18456 18457 18458 18459 18460 18461 18462 18463 18464 18465 18466 18467 18468 18469 |
{
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
return -1;
}
return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
}
int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
{
Jim_HashTable *ht;
unsigned int i;
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
return JIM_ERR;
}
ht = (Jim_HashTable *)objPtr->internalRep.ptr;
printf("%d entries in table, %d buckets\n", ht->used, ht->size);
for (i = 0; i < ht->size; i++) {
Jim_HashEntry *he = ht->table[i];
if (he) {
printf("%d: ", i);
while (he) {
printf(" %s", Jim_String(he->key));
he = he->next;
}
printf("\n");
}
}
return JIM_OK;
}
static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv)
{
Jim_Obj *prefixObj = Jim_NewStringObj(interp, basecmd, -1);
Jim_AppendString(interp, prefixObj, " ", 1);
Jim_AppendString(interp, prefixObj, subcmd, -1);
return Jim_EvalObjPrefix(interp, prefixObj, argc, argv);
}
static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *objPtr;
int option;
static const char * const options[] = {
"create", "get", "set", "unset", "exists", "keys", "size", "info",
"merge", "with", "append", "lappend", "incr", "remove", "values", "for",
"replace", "update", NULL
};
enum
{
OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXISTS, OPT_KEYS, OPT_SIZE, OPT_INFO,
OPT_MERGE, OPT_WITH, OPT_APPEND, OPT_LAPPEND, OPT_INCR, OPT_REMOVE, OPT_VALUES, OPT_FOR,
OPT_REPLACE, OPT_UPDATE,
};
if (argc < 2) {
Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?");
return JIM_ERR;
}
if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) {
return JIM_ERR;
}
switch (option) {
case OPT_GET:
if (argc < 3) {
Jim_WrongNumArgs(interp, 2, argv, "dictionary ?key ...?");
return JIM_ERR;
}
if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
JIM_ERRMSG) != JIM_OK) {
return JIM_ERR;
}
Jim_SetResult(interp, objPtr);
return JIM_OK;
case OPT_SET:
if (argc < 5) {
Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value");
return JIM_ERR;
}
return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
case OPT_EXISTS:
if (argc < 4) {
Jim_WrongNumArgs(interp, 2, argv, "dictionary key ?key ...?");
return JIM_ERR;
}
else {
int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_ERRMSG);
if (rc < 0) {
return JIM_ERR;
}
Jim_SetResultBool(interp, rc == JIM_OK);
return JIM_OK;
}
case OPT_UNSET:
if (argc < 4) {
Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?");
return JIM_ERR;
}
if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, 0) != JIM_OK) {
return JIM_ERR;
}
return JIM_OK;
case OPT_KEYS:
if (argc != 3 && argc != 4) {
Jim_WrongNumArgs(interp, 2, argv, "dictionary ?pattern?");
return JIM_ERR;
}
return Jim_DictKeys(interp, argv[2], argc == 4 ? argv[3] : NULL);
case OPT_SIZE:
if (argc != 3) {
Jim_WrongNumArgs(interp, 2, argv, "dictionary");
return JIM_ERR;
}
else if (Jim_DictSize(interp, argv[2]) < 0) {
return JIM_ERR;
}
Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2]));
return JIM_OK;
case OPT_MERGE:
if (argc == 2) {
return JIM_OK;
}
if (Jim_DictSize(interp, argv[2]) < 0) {
return JIM_ERR;
}
break;
case OPT_UPDATE:
if (argc < 6 || argc % 2) {
argc = 2;
}
break;
case OPT_CREATE:
if (argc % 2) {
Jim_WrongNumArgs(interp, 2, argv, "?key value ...?");
return JIM_ERR;
}
objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
Jim_SetResult(interp, objPtr);
return JIM_OK;
case OPT_INFO:
if (argc != 3) {
Jim_WrongNumArgs(interp, 2, argv, "dictionary");
return JIM_ERR;
}
return Jim_DictInfo(interp, argv[2]);
}
return Jim_EvalEnsemble(interp, "dict", options[option], argc - 2, argv + 2);
}
static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
static const char * const options[] = {
"-nobackslashes", "-nocommands", "-novariables", NULL
|
| ︙ | ︙ | |||
18265 18266 18267 18268 18269 18270 18271 |
"script", "source", "stacktrace", "nameofexecutable", "returncodes",
"references", "alias", NULL
};
enum
{ INFO_BODY, INFO_STATICS, INFO_COMMANDS, INFO_PROCS, INFO_CHANNELS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
INFO_FRAME, INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS,
INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE,
| | | 18517 18518 18519 18520 18521 18522 18523 18524 18525 18526 18527 18528 18529 18530 18531 |
"script", "source", "stacktrace", "nameofexecutable", "returncodes",
"references", "alias", NULL
};
enum
{ INFO_BODY, INFO_STATICS, INFO_COMMANDS, INFO_PROCS, INFO_CHANNELS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
INFO_FRAME, INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS,
INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE,
INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS,
};
#ifdef jim_ext_namespace
int nons = 0;
if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
|
| ︙ | ︙ | |||
19045 19046 19047 19048 19049 19050 19051 |
Jim_SetResultInt(interp, min+r);
return JIM_OK;
}
}
static const struct {
const char *name;
| | | 19297 19298 19299 19300 19301 19302 19303 19304 19305 19306 19307 19308 19309 19310 19311 |
Jim_SetResultInt(interp, min+r);
return JIM_OK;
}
}
static const struct {
const char *name;
Jim_CmdProc *cmdProc;
} Jim_CoreCommandsTable[] = {
{"alias", Jim_AliasCoreCommand},
{"set", Jim_SetCoreCommand},
{"unset", Jim_UnsetCoreCommand},
{"puts", Jim_PutsCoreCommand},
{"+", Jim_AddCoreCommand},
{"*", Jim_MulCoreCommand},
|
| ︙ | ︙ | |||
19277 19278 19279 19280 19281 19282 19283 19284 19285 19286 19287 19288 19289 19290 |
n++;
extra += l;
}
len += extra;
buf = Jim_Alloc(len + 1);
len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
}
#ifndef jim_ext_package
int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
| > > | 19529 19530 19531 19532 19533 19534 19535 19536 19537 19538 19539 19540 19541 19542 19543 19544 |
n++;
extra += l;
}
len += extra;
buf = Jim_Alloc(len + 1);
len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
va_end(args);
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
}
#ifndef jim_ext_package
int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
|
| ︙ | ︙ | |||
19528 19529 19530 19531 19532 19533 19534 |
}
}
#include <ctype.h>
#include <string.h>
| < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | < | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > < < < > | > | | > > > | | | | | | | | | | 19782 19783 19784 19785 19786 19787 19788 19789 19790 19791 19792 19793 19794 19795 19796 19797 19798 19799 19800 19801 19802 19803 19804 19805 19806 19807 19808 19809 19810 19811 19812 19813 19814 19815 19816 19817 19818 19819 19820 19821 19822 19823 19824 19825 19826 19827 19828 19829 19830 19831 19832 19833 19834 19835 19836 19837 19838 19839 19840 19841 19842 19843 19844 19845 19846 19847 19848 19849 19850 19851 19852 19853 19854 19855 19856 19857 19858 19859 19860 19861 19862 19863 19864 19865 19866 19867 19868 19869 19870 19871 19872 19873 19874 19875 19876 19877 19878 19879 19880 19881 19882 19883 19884 19885 19886 19887 19888 19889 19890 19891 19892 19893 19894 19895 19896 19897 19898 19899 19900 19901 19902 19903 19904 19905 19906 19907 19908 19909 19910 19911 19912 19913 19914 19915 19916 19917 19918 19919 19920 19921 19922 19923 19924 19925 19926 19927 19928 19929 19930 19931 19932 19933 19934 19935 19936 19937 19938 19939 19940 19941 19942 19943 19944 19945 19946 19947 19948 19949 19950 19951 19952 19953 19954 19955 19956 19957 19958 19959 19960 19961 19962 19963 19964 19965 19966 19967 19968 19969 19970 19971 19972 19973 19974 19975 19976 19977 19978 19979 19980 19981 19982 19983 19984 19985 19986 19987 19988 19989 19990 19991 19992 19993 19994 19995 19996 19997 19998 19999 20000 20001 20002 20003 20004 20005 20006 20007 20008 20009 20010 20011 20012 20013 20014 20015 20016 20017 20018 20019 20020 20021 20022 20023 20024 20025 20026 20027 20028 20029 20030 20031 20032 20033 20034 20035 20036 20037 20038 20039 20040 20041 20042 20043 20044 20045 20046 20047 20048 20049 20050 20051 20052 20053 20054 20055 20056 20057 20058 20059 20060 20061 20062 20063 20064 20065 20066 20067 20068 20069 20070 20071 20072 20073 20074 20075 20076 20077 20078 20079 20080 20081 20082 20083 20084 20085 20086 20087 20088 20089 20090 20091 20092 20093 20094 20095 20096 20097 20098 20099 20100 20101 20102 20103 20104 20105 20106 20107 20108 20109 20110 20111 20112 20113 20114 20115 20116 20117 20118 20119 20120 20121 20122 20123 20124 20125 20126 20127 20128 20129 20130 20131 20132 20133 20134 20135 20136 20137 20138 20139 20140 20141 20142 20143 20144 20145 20146 20147 20148 20149 20150 20151 20152 20153 20154 20155 20156 20157 20158 20159 20160 20161 20162 20163 20164 20165 20166 20167 20168 20169 20170 20171 20172 20173 20174 20175 20176 20177 20178 20179 20180 20181 20182 20183 20184 20185 20186 20187 20188 20189 20190 20191 20192 20193 20194 20195 20196 20197 20198 20199 20200 20201 20202 20203 20204 20205 20206 20207 20208 20209 20210 20211 20212 20213 20214 20215 20216 20217 20218 20219 20220 20221 20222 20223 20224 20225 20226 20227 20228 20229 20230 20231 20232 20233 20234 20235 20236 20237 20238 20239 20240 20241 20242 20243 20244 |
}
}
#include <ctype.h>
#include <string.h>
#define JIM_INTEGER_SPACE 24
#define MAX_FLOAT_WIDTH 320
Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
{
const char *span, *format, *formatEnd, *msg;
int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
static const char * const mixedXPG =
"cannot mix \"%\" and \"%n$\" conversion specifiers";
static const char * const badIndex[2] = {
"not enough arguments for all format specifiers",
"\"%n$\" argument index out of range"
};
int formatLen;
Jim_Obj *resultPtr;
char *num_buffer = NULL;
int num_buffer_size = 0;
span = format = Jim_GetString(fmtObjPtr, &formatLen);
formatEnd = format + formatLen;
resultPtr = Jim_NewEmptyStringObj(interp);
while (format != formatEnd) {
char *end;
int gotMinus, sawFlag;
int gotPrecision, useShort;
long width, precision;
int newXpg;
int ch;
int step;
int doubleType;
char pad = ' ';
char spec[2*JIM_INTEGER_SPACE + 12];
char *p;
int formatted_chars;
int formatted_bytes;
const char *formatted_buf;
step = utf8_tounicode(format, &ch);
format += step;
if (ch != '%') {
numBytes += step;
continue;
}
if (numBytes) {
Jim_AppendString(interp, resultPtr, span, numBytes);
numBytes = 0;
}
step = utf8_tounicode(format, &ch);
if (ch == '%') {
span = format;
numBytes = step;
format += step;
continue;
}
newXpg = 0;
if (isdigit(ch)) {
int position = strtoul(format, &end, 10);
if (*end == '$') {
newXpg = 1;
objIndex = position - 1;
format = end + 1;
step = utf8_tounicode(format, &ch);
}
}
if (newXpg) {
if (gotSequential) {
msg = mixedXPG;
goto errorMsg;
}
gotXpg = 1;
} else {
if (gotXpg) {
msg = mixedXPG;
goto errorMsg;
}
gotSequential = 1;
}
if ((objIndex < 0) || (objIndex >= objc)) {
msg = badIndex[gotXpg];
goto errorMsg;
}
p = spec;
*p++ = '%';
gotMinus = 0;
sawFlag = 1;
do {
switch (ch) {
case '-':
gotMinus = 1;
break;
case '0':
pad = ch;
break;
case ' ':
case '+':
case '#':
break;
default:
sawFlag = 0;
continue;
}
*p++ = ch;
format += step;
step = utf8_tounicode(format, &ch);
} while (sawFlag);
width = 0;
if (isdigit(ch)) {
width = strtoul(format, &end, 10);
format = end;
step = utf8_tounicode(format, &ch);
} else if (ch == '*') {
if (objIndex >= objc - 1) {
msg = badIndex[gotXpg];
goto errorMsg;
}
if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
goto error;
}
if (width < 0) {
width = -width;
if (!gotMinus) {
*p++ = '-';
gotMinus = 1;
}
}
objIndex++;
format += step;
step = utf8_tounicode(format, &ch);
}
gotPrecision = precision = 0;
if (ch == '.') {
gotPrecision = 1;
format += step;
step = utf8_tounicode(format, &ch);
}
if (isdigit(ch)) {
precision = strtoul(format, &end, 10);
format = end;
step = utf8_tounicode(format, &ch);
} else if (ch == '*') {
if (objIndex >= objc - 1) {
msg = badIndex[gotXpg];
goto errorMsg;
}
if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
goto error;
}
if (precision < 0) {
precision = 0;
}
objIndex++;
format += step;
step = utf8_tounicode(format, &ch);
}
useShort = 0;
if (ch == 'h') {
useShort = 1;
format += step;
step = utf8_tounicode(format, &ch);
} else if (ch == 'l') {
format += step;
step = utf8_tounicode(format, &ch);
if (ch == 'l') {
format += step;
step = utf8_tounicode(format, &ch);
}
}
format += step;
span = format;
if (ch == 'i') {
ch = 'd';
}
doubleType = 0;
switch (ch) {
case '\0':
msg = "format string ended in middle of field specifier";
goto errorMsg;
case 's': {
formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
if (gotPrecision && (precision < formatted_chars)) {
formatted_chars = precision;
formatted_bytes = utf8_index(formatted_buf, precision);
}
break;
}
case 'c': {
jim_wide code;
if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
goto error;
}
formatted_bytes = utf8_getchars(spec, code);
formatted_buf = spec;
formatted_chars = 1;
break;
}
case 'b': {
unsigned jim_wide w;
int length;
int i;
int j;
if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) {
goto error;
}
length = sizeof(w) * 8;
if (num_buffer_size < length + 1) {
num_buffer_size = length + 1;
num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
}
j = 0;
for (i = length; i > 0; ) {
i--;
if (w & ((unsigned jim_wide)1 << i)) {
num_buffer[j++] = '1';
}
else if (j || i == 0) {
num_buffer[j++] = '0';
}
}
num_buffer[j] = 0;
formatted_chars = formatted_bytes = j;
formatted_buf = num_buffer;
break;
}
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
doubleType = 1;
case 'd':
case 'u':
case 'o':
case 'x':
case 'X': {
jim_wide w;
double d;
int length;
if (width) {
p += sprintf(p, "%ld", width);
}
if (gotPrecision) {
p += sprintf(p, ".%ld", precision);
}
if (doubleType) {
if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
goto error;
}
length = MAX_FLOAT_WIDTH;
}
else {
if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
goto error;
}
length = JIM_INTEGER_SPACE;
if (useShort) {
if (ch == 'd') {
w = (short)w;
}
else {
w = (unsigned short)w;
}
}
*p++ = 'l';
#ifdef HAVE_LONG_LONG
if (sizeof(long long) == sizeof(jim_wide)) {
*p++ = 'l';
}
#endif
}
*p++ = (char) ch;
*p = '\0';
if (width > length) {
length = width;
}
if (gotPrecision) {
length += precision;
}
if (num_buffer_size < length + 1) {
num_buffer_size = length + 1;
num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
}
if (doubleType) {
snprintf(num_buffer, length + 1, spec, d);
}
else {
formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
}
formatted_chars = formatted_bytes = strlen(num_buffer);
formatted_buf = num_buffer;
break;
}
default: {
spec[0] = ch;
spec[1] = '\0';
Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
goto error;
}
}
if (!gotMinus) {
while (formatted_chars < width) {
Jim_AppendString(interp, resultPtr, &pad, 1);
formatted_chars++;
}
}
Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
while (formatted_chars < width) {
Jim_AppendString(interp, resultPtr, &pad, 1);
formatted_chars++;
}
objIndex += gotSequential;
}
if (numBytes) {
Jim_AppendString(interp, resultPtr, span, numBytes);
}
Jim_Free(num_buffer);
return resultPtr;
errorMsg:
Jim_SetResultString(interp, msg, -1);
error:
Jim_FreeNewObj(interp, resultPtr);
Jim_Free(num_buffer);
return NULL;
}
#if defined(JIM_REGEXP)
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#define REG_MAX_PAREN 100
#define END 0
#define BOL 1
#define EOL 2
#define ANY 3
#define ANYOF 4
#define ANYBUT 5
#define BRANCH 6
#define BACK 7
#define EXACTLY 8
#define NOTHING 9
#define REP 10
#define REPMIN 11
#define REPX 12
#define REPXMIN 13
#define WORDA 15
#define WORDZ 16
#define OPENNC 1000
#define OPEN 1001
#define CLOSENC 2000
#define CLOSE 2001
#define CLOSE_END (CLOSE+REG_MAX_PAREN)
#define REG_MAGIC 0xFADED00D
#define OP(preg, p) (preg->program[p])
#define NEXT(preg, p) (preg->program[p + 1])
#define OPERAND(p) ((p) + 2)
#define FAIL(R,M) { (R)->err = (M); return (M); }
#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
#define META "^$.[()|?{+*"
#define HASWIDTH 1
#define SIMPLE 2
#define SPSTART 4
#define WORST 0
#define MAX_REP_COUNT 1000000
static int reg(regex_t *preg, int paren , int *flagp );
static int regpiece(regex_t *preg, int *flagp );
static int regbranch(regex_t *preg, int *flagp );
static int regatom(regex_t *preg, int *flagp );
static int regnode(regex_t *preg, int op );
static int regnext(regex_t *preg, int p );
static void regc(regex_t *preg, int b );
static int reginsert(regex_t *preg, int op, int size, int opnd );
static void regtail(regex_t *preg, int p, int val);
static void regoptail(regex_t *preg, int p, int val );
static int regopsize(regex_t *preg, int p );
static int reg_range_find(const int *string, int c);
static const char *str_find(const char *string, int c, int nocase);
static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
#ifdef DEBUG
|
| ︙ | ︙ | |||
19983 19984 19985 19986 19987 19988 19989 | if (exp == NULL) FAIL(preg, REG_ERR_NULL_ARGUMENT); preg->cflags = cflags; preg->regparse = exp; | < < < | 20271 20272 20273 20274 20275 20276 20277 20278 20279 20280 20281 20282 20283 20284 | if (exp == NULL) FAIL(preg, REG_ERR_NULL_ARGUMENT); preg->cflags = cflags; preg->regparse = exp; preg->proglen = (strlen(exp) + 1) * 5; preg->program = malloc(preg->proglen * sizeof(int)); if (preg->program == NULL) FAIL(preg, REG_ERR_NOMEM); |
| ︙ | ︙ | |||
20150 20151 20152 20153 20154 20155 20156 |
static int regpiece(regex_t *preg, int *flagp)
{
int ret;
char op;
int next;
int flags;
| < | 20435 20436 20437 20438 20439 20440 20441 20442 20443 20444 20445 20446 20447 20448 |
static int regpiece(regex_t *preg, int *flagp)
{
int ret;
char op;
int next;
int flags;
int min;
int max;
ret = regatom(preg, &flags);
if (ret == 0)
return 0;
|
| ︙ | ︙ | |||
20233 20234 20235 20236 20237 20238 20239 |
preg->regparse++;
if (ISMULT(*preg->regparse)) {
preg->err = REG_ERR_NESTED_COUNT;
return 0;
}
| | | 20517 20518 20519 20520 20521 20522 20523 20524 20525 20526 20527 20528 20529 20530 20531 |
preg->regparse++;
if (ISMULT(*preg->regparse)) {
preg->err = REG_ERR_NESTED_COUNT;
return 0;
}
return ret;
}
static void reg_addrange(regex_t *preg, int lower, int upper)
{
if (lower > upper) {
reg_addrange(preg, upper, lower);
}
|
| ︙ | ︙ | |||
20327 20328 20329 20330 20331 20332 20333 20334 20335 20336 20337 20338 20339 20340 |
s += n;
}
break;
case 'U':
if ((n = parse_hex(s, 8, ch)) > 0) {
s += n;
}
case 'x':
if ((n = parse_hex(s, 2, ch)) > 0) {
s += n;
}
break;
case '\0':
s--;
| > | 20611 20612 20613 20614 20615 20616 20617 20618 20619 20620 20621 20622 20623 20624 20625 |
s += n;
}
break;
case 'U':
if ((n = parse_hex(s, 8, ch)) > 0) {
s += n;
}
break;
case 'x':
if ((n = parse_hex(s, 2, ch)) > 0) {
s += n;
}
break;
case '\0':
s--;
|
| ︙ | ︙ | |||
20575 20576 20577 20578 20579 20580 20581 20582 20583 20584 20585 20586 20587 20588 |
}
static int regnode(regex_t *preg, int op)
{
reg_grow(preg, 2);
preg->program[preg->p++] = op;
preg->program[preg->p++] = 0;
return preg->p - 2;
}
| > | 20860 20861 20862 20863 20864 20865 20866 20867 20868 20869 20870 20871 20872 20873 20874 |
}
static int regnode(regex_t *preg, int op)
{
reg_grow(preg, 2);
preg->program[preg->p++] = op;
preg->program[preg->p++] = 0;
return preg->p - 2;
}
|
| ︙ | ︙ | |||
20604 20605 20606 20607 20608 20609 20610 | preg->program[opnd] = op; preg->p += size; return opnd + size; } | | | 20890 20891 20892 20893 20894 20895 20896 20897 20898 20899 20900 20901 20902 20903 20904 |
preg->program[opnd] = op;
preg->p += size;
return opnd + size;
}
static void regtail(regex_t *preg, int p, int val)
{
int scan;
int temp;
int offset;
scan = p;
|
| ︙ | ︙ | |||
20667 20668 20669 20670 20671 20672 20673 | preg->eflags = eflags; preg->pmatch = pmatch; preg->nmatch = nmatch; preg->start = string; | | | < < < < < | | < < < < | < < < < < < < < < < < | 20953 20954 20955 20956 20957 20958 20959 20960 20961 20962 20963 20964 20965 20966 20967 20968 20969 20970 20971 20972 |
preg->eflags = eflags;
preg->pmatch = pmatch;
preg->nmatch = nmatch;
preg->start = string;
for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
int op = OP(preg, scan);
if (op == END)
break;
if (op == REPX || op == REPXMIN)
preg->program[scan + 4] = 0;
}
if (preg->regmust != 0) {
s = string;
while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
|
| ︙ | ︙ | |||
20948 20949 20950 20951 20952 20953 20954 20955 20956 20957 20958 20959 20960 20961 |
}
static int regmatch(regex_t *preg, int prog)
{
int scan;
int next;
scan = prog;
#ifdef DEBUG
if (scan != 0 && regnarrate)
fprintf(stderr, "%s(\n", regprop(scan));
#endif
| > | 21214 21215 21216 21217 21218 21219 21220 21221 21222 21223 21224 21225 21226 21227 21228 |
}
static int regmatch(regex_t *preg, int prog)
{
int scan;
int next;
const char *save;
scan = prog;
#ifdef DEBUG
if (scan != 0 && regnarrate)
fprintf(stderr, "%s(\n", regprop(scan));
#endif
|
| ︙ | ︙ | |||
21036 21037 21038 21039 21040 21041 21042 | } preg->reginput += n; break; case NOTHING: break; case BACK: break; | | < < | | | | | | | | | | | | | < | < | < < < < < < < | | < > | | 21303 21304 21305 21306 21307 21308 21309 21310 21311 21312 21313 21314 21315 21316 21317 21318 21319 21320 21321 21322 21323 21324 21325 21326 21327 21328 21329 21330 21331 21332 21333 21334 21335 21336 21337 21338 21339 21340 21341 21342 21343 21344 21345 21346 21347 21348 21349 21350 21351 21352 21353 21354 21355 21356 21357 21358 21359 21360 21361 21362 21363 21364 21365 21366 |
}
preg->reginput += n;
break;
case NOTHING:
break;
case BACK:
break;
case BRANCH:
if (OP(preg, next) != BRANCH)
next = OPERAND(scan);
else {
do {
save = preg->reginput;
if (regmatch(preg, OPERAND(scan))) {
return(1);
}
preg->reginput = save;
scan = regnext(preg, scan);
} while (scan != 0 && OP(preg, scan) == BRANCH);
return(0);
}
break;
case REP:
case REPMIN:
return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
case REPX:
case REPXMIN:
return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
case END:
return 1;
case OPENNC:
case CLOSENC:
return regmatch(preg, next);
default:
if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
save = preg->reginput;
if (regmatch(preg, next)) {
if (OP(preg, scan) < CLOSE) {
int no = OP(preg, scan) - OPEN;
if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
preg->pmatch[no].rm_so = save - preg->start;
}
}
else {
int no = OP(preg, scan) - CLOSE;
if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
preg->pmatch[no].rm_eo = save - preg->start;
}
}
return(1);
}
return(0);
}
return REG_ERR_INTERNAL;
}
scan = next;
}
|
| ︙ | ︙ | |||
21179 21180 21181 21182 21183 21184 21185 21186 21187 21188 21189 21190 21191 21192 |
return 0;
if (OP(preg, p) == BACK)
return(p-offset);
else
return(p+offset);
}
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
{
static const char *error_strings[] = {
"success",
"no match",
| > > > > > > > > > > > > > > > > > > > > > > | 21435 21436 21437 21438 21439 21440 21441 21442 21443 21444 21445 21446 21447 21448 21449 21450 21451 21452 21453 21454 21455 21456 21457 21458 21459 21460 21461 21462 21463 21464 21465 21466 21467 21468 21469 21470 |
return 0;
if (OP(preg, p) == BACK)
return(p-offset);
else
return(p+offset);
}
static int regopsize(regex_t *preg, int p )
{
switch (OP(preg, p)) {
case REP:
case REPMIN:
case REPX:
case REPXMIN:
return 5;
case ANYOF:
case ANYBUT:
case EXACTLY: {
int s = p + 2;
while (preg->program[s++]) {
}
return s - p;
}
}
return 2;
}
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
{
static const char *error_strings[] = {
"success",
"no match",
|
| ︙ | ︙ | |||
21357 21358 21359 21360 21361 21362 21363 21364 21365 21366 21367 21368 21369 21370 21371 21372 21373 21374 21375 21376 21377 21378 21379 |
#endif
char *Jim_HistoryGetline(const char *prompt)
{
#ifdef USE_LINENOISE
return linenoise(prompt);
#else
char *line = malloc(MAX_LINE_LEN);
fputs(prompt, stdout);
fflush(stdout);
if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
free(line);
return NULL;
}
return line;
#endif
}
void Jim_HistoryLoad(const char *filename)
{
#ifdef USE_LINENOISE
| > > > > > | 21635 21636 21637 21638 21639 21640 21641 21642 21643 21644 21645 21646 21647 21648 21649 21650 21651 21652 21653 21654 21655 21656 21657 21658 21659 21660 21661 21662 |
#endif
char *Jim_HistoryGetline(const char *prompt)
{
#ifdef USE_LINENOISE
return linenoise(prompt);
#else
int len;
char *line = malloc(MAX_LINE_LEN);
fputs(prompt, stdout);
fflush(stdout);
if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
free(line);
return NULL;
}
len = strlen(line);
if (len && line[len - 1] == '\n') {
line[len - 1] = '\0';
}
return line;
#endif
}
void Jim_HistoryLoad(const char *filename)
{
#ifdef USE_LINENOISE
|
| ︙ | ︙ | |||
21420 21421 21422 21423 21424 21425 21426 |
int history_len = strlen(home) + sizeof("/.jim_history");
history_file = Jim_Alloc(history_len);
snprintf(history_file, history_len, "%s/.jim_history", home);
Jim_HistoryLoad(history_file);
}
#endif
| | | 21703 21704 21705 21706 21707 21708 21709 21710 21711 21712 21713 21714 21715 21716 21717 |
int history_len = strlen(home) + sizeof("/.jim_history");
history_file = Jim_Alloc(history_len);
snprintf(history_file, history_len, "%s/.jim_history", home);
Jim_HistoryLoad(history_file);
}
#endif
printf("Welcome to Jim version %d.%d\n",
JIM_VERSION / 100, JIM_VERSION % 100);
Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
while (1) {
Jim_Obj *scriptObjPtr;
const char *result;
int reslen;
|
| ︙ | ︙ | |||
21532 21533 21534 21535 21536 21537 21538 21539 21540 21541 21542 21543 21544 21545 21546 21547 21548 21549 21550 21551 21552 21553 21554 21555 |
Jim_ListAppendElement(interp, listObj, obj);
}
Jim_SetVariableStr(interp, "argv", listObj);
Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
}
int main(int argc, char *const argv[])
{
int retcode;
Jim_Interp *interp;
if (argc > 1 && strcmp(argv[1], "--version") == 0) {
printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
return 0;
}
interp = Jim_CreateInterp();
Jim_RegisterCoreCommands(interp);
if (Jim_InitStaticExtensions(interp) != JIM_OK) {
| > > > > > > | < | < | < | 21815 21816 21817 21818 21819 21820 21821 21822 21823 21824 21825 21826 21827 21828 21829 21830 21831 21832 21833 21834 21835 21836 21837 21838 21839 21840 21841 21842 21843 21844 21845 21846 21847 21848 21849 21850 21851 21852 21853 21854 21855 21856 21857 21858 21859 21860 21861 21862 21863 21864 21865 21866 21867 21868 21869 21870 21871 21872 21873 21874 21875 21876 21877 21878 21879 21880 21881 21882 |
Jim_ListAppendElement(interp, listObj, obj);
}
Jim_SetVariableStr(interp, "argv", listObj);
Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
}
static void JimPrintErrorMessage(Jim_Interp *interp)
{
Jim_MakeErrorMessage(interp);
fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
}
int main(int argc, char *const argv[])
{
int retcode;
Jim_Interp *interp;
if (argc > 1 && strcmp(argv[1], "--version") == 0) {
printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
return 0;
}
interp = Jim_CreateInterp();
Jim_RegisterCoreCommands(interp);
if (Jim_InitStaticExtensions(interp) != JIM_OK) {
JimPrintErrorMessage(interp);
}
Jim_SetVariableStrWithStr(interp, "jim_argv0", argv[0]);
Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
retcode = Jim_initjimshInit(interp);
if (argc == 1) {
if (retcode == JIM_ERR) {
JimPrintErrorMessage(interp);
}
if (retcode != JIM_EXIT) {
JimSetArgv(interp, 0, NULL);
retcode = Jim_InteractivePrompt(interp);
}
}
else {
if (argc > 2 && strcmp(argv[1], "-e") == 0) {
JimSetArgv(interp, argc - 3, argv + 3);
retcode = Jim_Eval(interp, argv[2]);
if (retcode != JIM_ERR) {
printf("%s\n", Jim_String(Jim_GetResult(interp)));
}
}
else {
Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
JimSetArgv(interp, argc - 2, argv + 2);
retcode = Jim_EvalFile(interp, argv[1]);
}
if (retcode == JIM_ERR) {
JimPrintErrorMessage(interp);
}
}
if (retcode == JIM_EXIT) {
retcode = Jim_GetExitCode(interp);
}
else if (retcode == JIM_ERR) {
retcode = 1;
|
| ︙ | ︙ |
Changes to src/add.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
"_FOSSIL_-wal",
"_FOSSIL_-shm",
".fslckout",
".fslckout-journal",
".fslckout-wal",
".fslckout-shm",
| | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
"_FOSSIL_-wal",
"_FOSSIL_-shm",
".fslckout",
".fslckout-journal",
".fslckout-wal",
".fslckout-shm",
/* The use of ".fos" as the name of the checkout database is
** deprecated. Use ".fslckout" instead. At some point, the following
** entries should be removed. 2012-02-04 */
".fos",
".fos-journal",
".fos-wal",
".fos-shm",
};
|
| ︙ | ︙ | |||
121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
**
** Show all reserved filenames for the current check-out.
*/
void test_reserved_names(void){
int i;
const char *z;
int omitRepo = find_option("omitrepo",0,0)!=0;
db_must_be_within_tree();
for(i=0; (z = fossil_reserved_name(i, omitRepo))!=0; i++){
fossil_print("%3d: %s\n", i, z);
}
fossil_print("ALL: (%s)\n", fossil_all_reserved_names(omitRepo));
}
| > > > > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
**
** Show all reserved filenames for the current check-out.
*/
void test_reserved_names(void){
int i;
const char *z;
int omitRepo = find_option("omitrepo",0,0)!=0;
/* We should be done with options.. */
verify_all_options();
db_must_be_within_tree();
for(i=0; (z = fossil_reserved_name(i, omitRepo))!=0; i++){
fossil_print("%3d: %s\n", i, z);
}
fossil_print("ALL: (%s)\n", fossil_all_reserved_names(omitRepo));
}
|
| ︙ | ︙ | |||
175 176 177 178 179 180 181 | const char *zRepo; /* Name of the repository database file */ int nAdd = 0; /* Number of files added */ int i; /* Loop counter */ const char *zReserved; /* Name of a reserved file */ Blob repoName; /* Treename of the repository */ Stmt loop; /* SQL to loop over all files to add */ int (*xCmp)(const char*,const char*); | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
const char *zRepo; /* Name of the repository database file */
int nAdd = 0; /* Number of files added */
int i; /* Loop counter */
const char *zReserved; /* Name of a reserved file */
Blob repoName; /* Treename of the repository */
Stmt loop; /* SQL to loop over all files to add */
int (*xCmp)(const char*,const char*);
if( !file_tree_name(g.zRepositoryName, &repoName, 0) ){
blob_zero(&repoName);
zRepo = "";
}else{
zRepo = blob_str(&repoName);
}
if( filenames_are_case_sensitive() ){
|
| ︙ | ︙ | |||
231 232 233 234 235 236 237 | ** The --case-sensitive option determines whether or not filenames should ** be treated case sensitive or not. If the option is not given, the default ** depends on the global setting, or the operating system default, if not set. ** ** Options: ** ** --case-sensitive <BOOL> override case-sensitive setting | | | | > > > > | | 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 |
** The --case-sensitive option determines whether or not filenames should
** be treated case sensitive or not. If the option is not given, the default
** depends on the global setting, or the operating system default, if not set.
**
** Options:
**
** --case-sensitive <BOOL> override case-sensitive setting
** --dotfiles include files beginning with a dot (".")
** -f|--force Add files without prompting
** --ignore <CSG> ignore files matching patterns from the
** comma separated list of glob patterns.
** --clean <CSG> also ignore files matching patterns from
** the comma separated list of glob patterns.
**
** See also: addremove, rm
*/
void add_cmd(void){
int i; /* Loop counter */
int vid; /* Currently checked out version */
int nRoot; /* Full path characters in g.zLocalRoot */
const char *zCleanFlag; /* The --clean option or clean-glob setting */
const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */
Glob *pIgnore, *pClean; /* Ignore everything matching the glob patterns */
unsigned scanFlags = 0; /* Flags passed to vfile_scan() */
int forceFlag;
zCleanFlag = find_option("clean",0,1);
zIgnoreFlag = find_option("ignore",0,1);
forceFlag = find_option("force","f",0)!=0;
if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
capture_case_sensitive_option();
/* We should be done with options.. */
verify_all_options();
db_must_be_within_tree();
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
|
| ︙ | ︙ | |||
344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
** 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;
| > > > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
** See also: addremove, add
*/
void delete_cmd(void){
int i;
Stmt loop;
capture_case_sensitive_option();
/* We should be done with options.. */
verify_all_options();
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;
|
| ︙ | ︙ | |||
365 366 367 368 369 370 371 |
" OR (pathname>'%q/' %s AND pathname<'%q0' %s))"
" AND NOT deleted",
zTreeName, filename_collation(), zTreeName,
filename_collation(), zTreeName, filename_collation()
);
blob_reset(&treeName);
}
| | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
" OR (pathname>'%q/' %s AND pathname<'%q0' %s))"
" AND NOT deleted",
zTreeName, filename_collation(), zTreeName,
filename_collation(), zTreeName, filename_collation()
);
blob_reset(&treeName);
}
db_prepare(&loop, "SELECT x FROM sfile");
while( db_step(&loop)==SQLITE_ROW ){
fossil_print("DELETED %s\n", db_column_text(&loop, 0));
}
db_finalize(&loop);
db_multi_exec(
"UPDATE vfile SET deleted=1 WHERE pathname IN sfile;"
|
| ︙ | ︙ | |||
480 481 482 483 484 485 486 | ** --case-sensitive option with the "case-sensitive" setting and the ** --clean option with the "clean-glob" setting. See the documentation ** on the "settings" command for further information. ** ** The -n|--dry-run option shows what would happen without actually doing anything. ** ** This command can be used to track third party software. | | | | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
** --case-sensitive option with the "case-sensitive" setting and the
** --clean option with the "clean-glob" setting. See the documentation
** on the "settings" command for further information.
**
** The -n|--dry-run option shows what would happen without actually doing anything.
**
** This command can be used to track third party software.
**
** Options:
** --case-sensitive <BOOL> override case-sensitive setting
** --dotfiles include files beginning with a dot (".")
** --ignore <CSG> ignore files matching patterns from the
** comma separated list of glob patterns.
** --clean <CSG> also ignore files matching patterns from
** the comma separated list of glob patterns.
** -n|--dry-run If given, display instead of run actions
|
| ︙ | ︙ | |||
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
int nDelete = 0;
Glob *pIgnore, *pClean;
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
capture_case_sensitive_option();
db_must_be_within_tree();
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();
| > > > > | | 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 |
int nDelete = 0;
Glob *pIgnore, *pClean;
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
capture_case_sensitive_option();
/* We should be done with options.. */
verify_all_options();
db_must_be_within_tree();
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());
|
| ︙ | ︙ | |||
545 546 547 548 549 550 551 |
db_prepare(&q,
"SELECT pathname, %Q || pathname, deleted FROM vfile"
" WHERE NOT deleted"
" ORDER BY 1",
g.zLocalRoot
);
while( db_step(&q)==SQLITE_ROW ){
| | | | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 |
db_prepare(&q,
"SELECT pathname, %Q || pathname, deleted FROM vfile"
" WHERE NOT deleted"
" ORDER BY 1",
g.zLocalRoot
);
while( db_step(&q)==SQLITE_ROW ){
const char *zFile;
const char *zPath;
zFile = db_column_text(&q, 0);
zPath = db_column_text(&q, 1);
if( !file_wd_isfile_or_link(zPath) ){
if( !dryRunFlag ){
db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zFile);
}
|
| ︙ | ︙ | |||
577 578 579 580 581 582 583 |
*/
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'"
| | | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 |
*/
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);
}
}
fossil_print("RENAME %s %s\n", zOrig, zNew);
db_multi_exec(
|
| ︙ | ︙ | |||
618 619 620 621 622 623 624 625 626 627 628 629 630 631 |
int vid;
char *zDest;
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");
}
| > > > > | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
int vid;
char *zDest;
Blob dest;
Stmt q;
capture_case_sensitive_option();
db_must_be_within_tree();
/* We should be done with options.. */
verify_all_options();
vid = db_lget_int("checkout", 0);
if( vid==0 ){
fossil_fatal("no checkout rename files in");
}
if( g.argc<4 ){
usage("OLDNAME NEWNAME");
}
|
| ︙ | ︙ |
Changes to src/browse.c.
| ︙ | ︙ | |||
493 494 495 496 497 498 499 |
zUuid);
}
}
if( linkTrunk ){
style_submenu_element("Trunk", "Trunk", "%s",
url_render(&sURI, "ci", "trunk", 0, 0));
}
| | | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
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));
}
|
| ︙ | ︙ | |||
716 717 718 719 720 721 722 |
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);
| | | 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 |
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;
}
/*
|
| ︙ | ︙ |
Changes to src/cache.c.
| ︙ | ︙ | |||
60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
rc = sqlite3_open(zDbName, &db);
fossil_free(zDbName);
if( rc ){
sqlite3_close(db);
return 0;
}
rc = sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS blob(id INTEGER PRIMARY KEY, data BLOB);"
"CREATE TABLE IF NOT EXISTS cache("
"key TEXT PRIMARY KEY," /* Key used to access the cache */
"id INT REFERENCES blob," /* The cache content */
"sz INT," /* Size of content in bytes */
"tm INT," /* Last access time (unix timestampe) */
"nref INT" /* Number of uses */
| > | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
rc = sqlite3_open(zDbName, &db);
fossil_free(zDbName);
if( rc ){
sqlite3_close(db);
return 0;
}
rc = sqlite3_exec(db,
"PRAGMA page_size=8192;"
"CREATE TABLE IF NOT EXISTS blob(id INTEGER PRIMARY KEY, data BLOB);"
"CREATE TABLE IF NOT EXISTS cache("
"key TEXT PRIMARY KEY," /* Key used to access the cache */
"id INT REFERENCES blob," /* The cache content */
"sz INT," /* Size of content in bytes */
"tm INT," /* Last access time (unix timestampe) */
"nref INT" /* Number of uses */
|
| ︙ | ︙ | |||
343 344 345 346 347 348 349 |
"SELECT key, sizename(sz), nRef, datetime(tm,'unixepoch')"
" FROM cache"
" ORDER BY tm DESC"
);
if( pStmt ){
@ <ol>
while( sqlite3_step(pStmt)==SQLITE_ROW ){
| | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
"SELECT key, sizename(sz), nRef, datetime(tm,'unixepoch')"
" FROM cache"
" ORDER BY tm DESC"
);
if( pStmt ){
@ <ol>
while( sqlite3_step(pStmt)==SQLITE_ROW ){
const char *zName = sqlite3_column_text(pStmt,0);
@ <li><p>%z(href("%R/cacheget?key=%T",zName))%h(zName)</a><br>
@ size: %s(sqlite3_column_text(pStmt,1))
@ hit-count: %d(sqlite3_column_int(pStmt,2))
@ last-access: %s(sqlite3_column_text(pStmt,3))</p></li>
}
sqlite3_finalize(pStmt);
@ </ol>
}
zDbName = cacheName();
bigSizeName(sizeof(zBuf), zBuf, file_size(zDbName));
@ <p>cache-file name: %h(zDbName)</p>
@ <p>cache-file size: %s(zBuf)</p>
fossil_free(zDbName);
sqlite3_close(db);
}
style_footer();
}
/*
** WEBPAGE: cacheget
**
** Usage: /cacheget?key=KEY
**
** Download a single entry for the cache, identified by KEY.
** This page is normally a hyperlink from the /cachestat page.
*/
void cache_getpage(void){
const char *zKey;
Blob content;
login_check_credentials();
if( !g.perm.Setup ){ login_needed(); return; }
zKey = PD("key","");
blob_zero(&content);
if( cache_read(&content, zKey)==0 ){
style_header("Cache Download Error");
@ The cache does not contain any entry with this key: "%h(zKey)"
style_footer();
return;
}
cgi_set_content(&content);
cgi_set_content_type("application/x-compressed");
}
|
Changes to src/cgi.c.
| ︙ | ︙ | |||
304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
}
#endif
if( g.fullHttpReply ){
fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
fprintf(g.httpOut, "Connection: close\r\n");
}else{
fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
}
if( blob_size(&extraHeader)>0 ){
fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
}
| > | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
}
#endif
if( g.fullHttpReply ){
fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
fprintf(g.httpOut, "Connection: close\r\n");
fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
}else{
fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
}
if( blob_size(&extraHeader)>0 ){
fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
}
|
| ︙ | ︙ | |||
748 749 750 751 752 753 754 |
unsigned int * n ){
if( ! state || !dest || !n ) return cson_rc.ArgError;
else {
CgiPostReadState * st = (CgiPostReadState *)state;
if( st->pos >= st->len ){
*n = 0;
return 0;
| | | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 |
unsigned int * n ){
if( ! state || !dest || !n ) return cson_rc.ArgError;
else {
CgiPostReadState * st = (CgiPostReadState *)state;
if( st->pos >= st->len ){
*n = 0;
return 0;
}else if( !*n || ((st->pos + *n) > st->len) ){
return cson_rc.RangeError;
}else{
unsigned int rsz = (unsigned int)fread( dest, 1, *n, st->fh );
if( ! rsz ){
*n = rsz;
return feof(st->fh) ? 0 : cson_rc.IOError;
}else{
|
| ︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 |
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 ){
| | | 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 |
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);
|
| ︙ | ︙ |
Changes to src/checkin.c.
| ︙ | ︙ | |||
157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
int relativePaths = db_get_boolean("relative-paths", 1);
int absPathOption = find_option("abs-paths", 0, 0)!=0;
int relPathOption = find_option("rel-paths", 0, 0)!=0;
if( absPathOption ){ relativePaths = 0; }
if( relPathOption ){ relativePaths = 1; }
return relativePaths;
}
/*
** COMMAND: changes
**
** Usage: %fossil changes ?OPTIONS?
**
** Report on the edit status of all files in the current checkout.
| > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
int relativePaths = db_get_boolean("relative-paths", 1);
int absPathOption = find_option("abs-paths", 0, 0)!=0;
int relPathOption = find_option("rel-paths", 0, 0)!=0;
if( absPathOption ){ relativePaths = 0; }
if( relPathOption ){ relativePaths = 1; }
return relativePaths;
}
void print_changes(
int useSha1sum, /* Verify file status using SHA1 hashing rather
than relying on file mtimes. */
int showHdr, /* Identify the repository if there are changes */
int verboseFlag, /* Say "(none)" if there are no changes */
int cwdRelative /* Report relative to the current working dir */
){
Blob report;
int vid;
blob_zero(&report);
vid = db_lget_int("checkout", 0);
vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
status_report(&report, "", 0, cwdRelative);
if( verboseFlag && blob_size(&report)==0 ){
blob_append(&report, " (none)\n", -1);
}
if( showHdr && blob_size(&report)>0 ){
fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
g.zLocalRoot);
}
blob_write_to_file(&report, "-");
blob_reset(&report);
}
/*
** COMMAND: changes
**
** Usage: %fossil changes ?OPTIONS?
**
** Report on the edit status of all files in the current checkout.
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 |
** than relying on file mtimes.
** --header Identify the repository if there are changes
** -v|--verbose Say "(none)" if there are no changes
**
** See also: extras, ls, status
*/
void changes_cmd(void){
| < < < < < < < < | | < | | < < > | 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 |
** than relying on file mtimes.
** --header Identify the repository if there are changes
** -v|--verbose Say "(none)" if there are no changes
**
** See also: extras, ls, status
*/
void changes_cmd(void){
int useSha1sum = find_option("sha1sum", 0, 0)!=0;
int showHdr = find_option("header",0,0)!=0;
int verboseFlag = find_option("verbose","v",0)!=0;
int cwdRelative = 0;
db_must_be_within_tree();
cwdRelative = determine_cwd_relative_option();
/* We should be done with options.. */
verify_all_options();
print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
}
/*
** COMMAND: status
**
** Usage: %fossil status ?OPTIONS?
**
|
| ︙ | ︙ | |||
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
** --sha1sum Verify file status using SHA1 hashing rather
** than relying on file mtimes.
**
** See also: changes, extras, ls
*/
void status_cmd(void){
int vid;
db_must_be_within_tree();
/* 012345678901234 */
fossil_print("repository: %s\n", db_repository_filename());
fossil_print("local-root: %s\n", g.zLocalRoot);
if( g.zConfigDbName ){
fossil_print("config-db: %s\n", g.zConfigDbName);
}
vid = db_lget_int("checkout", 0);
if( vid ){
show_common_info(vid, "checkout:", 1, 1);
}
| > > > > > > > > > | | | 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 |
** --sha1sum Verify file status using SHA1 hashing rather
** than relying on file mtimes.
**
** See also: changes, extras, ls
*/
void status_cmd(void){
int vid;
int useSha1sum = find_option("sha1sum", 0, 0)!=0;
int showHdr = find_option("header",0,0)!=0;
int verboseFlag = find_option("verbose","v",0)!=0;
int cwdRelative = 0;
db_must_be_within_tree();
/* 012345678901234 */
cwdRelative = determine_cwd_relative_option();
/* We should be done with options.. */
verify_all_options();
fossil_print("repository: %s\n", db_repository_filename());
fossil_print("local-root: %s\n", g.zLocalRoot);
if( g.zConfigDbName ){
fossil_print("config-db: %s\n", g.zConfigDbName);
}
vid = db_lget_int("checkout", 0);
if( vid ){
show_common_info(vid, "checkout:", 1, 1);
}
db_record_repository_filename(0);
print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
}
/*
** COMMAND: ls
**
** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
**
|
| ︙ | ︙ | |||
452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
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,
| > > > > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
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();
/* We should be done with options.. */
verify_all_options();
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,
|
| ︙ | ︙ |
Changes to src/checkout.c.
| ︙ | ︙ | |||
199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
db_must_be_within_tree();
db_begin_transaction();
forceFlag = find_option("force","f",0)!=0;
forceMissingFlag = find_option("force-missing",0,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) ){
fossil_fatal("there are unsaved changes in the current checkout");
}
if( forceFlag ){
| > > > > | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
db_must_be_within_tree();
db_begin_transaction();
forceFlag = find_option("force","f",0)!=0;
forceMissingFlag = find_option("force-missing",0,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;
/* We should be done with options.. */
verify_all_options();
if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){
usage("VERSION|--latest ?--force? ?--keep?");
}
if( !forceFlag && unsaved_changes(0) ){
fossil_fatal("there are unsaved changes in the current checkout");
}
if( forceFlag ){
|
| ︙ | ︙ | |||
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
** --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) ){
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") ){
| > > > > | | 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 |
** --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();
/* We should be done with options.. */
verify_all_options();
if( !forceFlag && unsaved_changes(0) ){
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") ){
char *zUnset = mprintf("ckout:%q", g.zLocalRoot);
db_unset(zUnset, 1);
fossil_free(zUnset);
}
unlink_local_database(1);
db_close(1);
unlink_local_database(0);
}
|
Changes to src/clone.c.
| ︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
zHttpAuth = find_option("httpauth","B",1);
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]);
}
| > > > > | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
zHttpAuth = find_option("httpauth","B",1);
zDefaultUser = find_option("admin-user","A",1);
clone_ssh_find_options();
url_proxy_options();
/* We should be done with options.. */
verify_all_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]);
}
|
| ︙ | ︙ |
Changes to src/comformat.c.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 | # include <sys/ioctl.h> # endif #endif #if INTERFACE #define COMMENT_PRINT_NONE ((u32)0x00000000) /* No flags. */ #define COMMENT_PRINT_LEGACY ((u32)0x00000001) /* Use legacy algorithm. */ | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
# include <sys/ioctl.h>
# endif
#endif
#if INTERFACE
#define COMMENT_PRINT_NONE ((u32)0x00000000) /* No flags. */
#define COMMENT_PRINT_LEGACY ((u32)0x00000001) /* Use legacy algorithm. */
#define COMMENT_PRINT_TRIM_CRLF ((u32)0x00000002) /* Trim leading CR/LF. */
#define COMMENT_PRINT_TRIM_SPACE ((u32)0x00000004) /* Trim leading/trailing. */
#define COMMENT_PRINT_WORD_BREAK ((u32)0x00000008) /* Break lines on words. */
#define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */
#define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */
#endif
/*
** This is the previous value used by most external callers when they
** needed to specify a default maximum line length to be used with the
** comment_print() function.
*/
#ifndef COMMENT_LEGACY_LINE_LENGTH
# define COMMENT_LEGACY_LINE_LENGTH (78)
#endif
/*
** This is the number of spaces to print when a tab character is seen.
*/
#ifndef COMMENT_TAB_WIDTH
# define COMMENT_TAB_WIDTH (8)
#endif
/*
** This function sets the maximum number of characters to print per line
** based on the detected terminal line width, if available; otherwise, it
** uses the legacy default terminal line width minus the amount to indent.
**
** Zero is returned to indicate any failure. One is returned to indicate
** the successful detection of the terminal line width. Negative one is
** returned to indicate the terminal line width is using the hard-coded
** legacy default value.
*/
static int comment_set_maxchars(
int indent,
int *pMaxChars
){
#if defined(_WIN32)
CONSOLE_SCREEN_BUFFER_INFO csbi;
memset(&csbi, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFO));
if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) ){
*pMaxChars = csbi.srWindow.Right - csbi.srWindow.Left - indent;
return 1;
}
return 0;
#elif defined(TIOCGWINSZ)
struct winsize w;
memset(&w, 0, sizeof(struct winsize));
if( ioctl(0, TIOCGWINSZ, &w)!=-1 ){
*pMaxChars = w.ws_col - indent;
return 1;
}
return 0;
#else
/*
** Fallback to using more-or-less the "legacy semantics" of hard-coding
** the maximum line length to a value reasonable for the vast majority
** of supported systems.
*/
*pMaxChars = COMMENT_LEGACY_LINE_LENGTH - indent;
return -1;
#endif
}
/*
** This function checks the current line being printed against the original
** comment text. Upon matching, it emits a new line and updates the provided
** character and line counts, if applicable.
*/
static int comment_check_orig(
|
| ︙ | ︙ | |||
99 100 101 102 103 104 105 106 107 108 109 110 |
/*
** This function is called when printing a logical comment line to perform
** the necessary indenting.
*/
static void comment_print_indent(
const char *zLine, /* [in] The comment line being printed. */
int indent, /* [in] Number of spaces to indent, zero for none. */
int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */
int *piIndex /* [in/out] Pointer to first non-space character. */
){
if( indent>0 ){
fossil_print("%*s", indent, "");
| > > | | > > > > < > > > | > > | > > | > > > | > | < < < > > > | 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 |
/*
** This function is called when printing a logical comment line to perform
** the necessary indenting.
*/
static void comment_print_indent(
const char *zLine, /* [in] The comment line being printed. */
int indent, /* [in] Number of spaces to indent, zero for none. */
int trimCrLf, /* [in] Non-zero to trim leading/trailing CR/LF. */
int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */
int *piIndex /* [in/out] Pointer to first non-space character. */
){
if( indent>0 ){
fossil_print("%*s", indent, "");
}
if( zLine && piIndex ){
int index = *piIndex;
if( trimCrLf ){
while( zLine[index]=='\r' || zLine[index]=='\n' ){ index++; }
}
if( trimSpace ){
while( fossil_isspace(zLine[index]) ){ index++; }
}
*piIndex = index;
}
}
/*
** This function prints one logical line of a comment, stopping when it hits
** a new line -OR- runs out of space on the logical line.
*/
static void comment_print_line(
const char *zOrigText, /* [in] Original comment text ONLY, may be NULL. */
const char *zLine, /* [in] The comment line to print. */
int origIndent, /* [in] Number of spaces to indent before the original
** comment. */
int indent, /* [in] Number of spaces to indent, before the line
** to print. */
int lineChars, /* [in] Maximum number of characters to print. */
int trimCrLf, /* [in] Non-zero to trim leading/trailing CR/LF. */
int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */
int wordBreak, /* [in] Non-zero to try breaking on word boundaries. */
int origBreak, /* [in] Non-zero to break before original comment. */
int *pLineCnt, /* [in/out] Pointer to the total line count. */
const char **pzLine /* [out] Pointer to the end of the logical line. */
){
int index = 0, charCnt = 0, lineCnt = 0, maxChars;
if( !zLine ) return;
if( lineChars<=0 ) return;
comment_print_indent(zLine, indent, trimCrLf, trimSpace, &index);
maxChars = lineChars;
for(;;){
int useChars = 1;
char c = zLine[index];
if( c==0 ){
break;
}else{
if( origBreak && index>0 ){
const char *zCurrent = &zLine[index];
if( comment_check_orig(zOrigText, zCurrent, &charCnt, &lineCnt) ){
comment_print_indent(zCurrent, origIndent, trimCrLf, trimSpace,
&index);
maxChars = lineChars;
}
}
index++;
}
if( c=='\n' ){
lineCnt++;
charCnt = 0;
useChars = 0;
}else if( c=='\t' ){
int nextIndex = comment_next_space(zLine, index);
if( nextIndex<=0 || (nextIndex-index)>maxChars ){
break;
}
charCnt++;
useChars = COMMENT_TAB_WIDTH;
if( maxChars<useChars ){
fossil_print(" ");
break;
}
}else if( wordBreak && fossil_isspace(c) ){
int nextIndex = comment_next_space(zLine, index);
if( nextIndex<=0 || (nextIndex-index)>maxChars ){
break;
}
charCnt++;
}else{
charCnt++;
}
assert( c!='\n' || charCnt==0 );
fossil_print("%c", c);
maxChars -= useChars;
if( maxChars==0 ) break;
assert( maxChars>0 );
if( c=='\n' ) break;
}
if( charCnt>0 ){
fossil_print("\n");
lineCnt++;
}
if( pLineCnt ){
|
| ︙ | ︙ | |||
201 202 203 204 205 206 207 |
** Returns the number of new lines emitted.
*/
static int comment_print_legacy(
const char *zText, /* The comment text to be printed. */
int indent, /* Number of spaces to indent each non-initial line. */
int width /* Maximum number of characters per line. */
){
| | < < < < < < < < < < < < | | < < < < < < < < < < < | | | | | | 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 |
** Returns the number of new lines emitted.
*/
static int comment_print_legacy(
const char *zText, /* The comment text to be printed. */
int indent, /* Number of spaces to indent each non-initial line. */
int width /* Maximum number of characters per line. */
){
int maxChars = width - indent;
int si, sk, i, k;
int doIndent = 0;
char *zBuf;
char zBuffer[400];
int lineCnt = 0;
if( width<0 ){
comment_set_maxchars(indent, &maxChars);
}
if( zText==0 ) zText = "(NULL)";
if( maxChars<=0 ){
maxChars = strlen(zText);
}
if( maxChars >= (sizeof(zBuffer)) ){
zBuf = fossil_malloc(maxChars+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<maxChars; i++){
char c = zText[i];
if( fossil_isspace(c) ){
si = i;
sk = k;
if( k==0 || zBuf[k-1]!=' ' ){
zBuf[k++] = ' ';
}
|
| ︙ | ︙ | |||
296 297 298 299 300 301 302 | ** the comment string itself while honoring line width limitations. There ** are several flags that modify the default behavior of this function: ** ** COMMENT_PRINT_LEGACY: Forces use of the legacy comment printing ** algorithm. For backward compatibility, ** this is the default. ** | > > > > > > > > > | | | | | > | > < < < < < < < < < < < < | | < < < < < < < < < < < | | > > > > > > > > > > > > > > | 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 |
** the comment string itself while honoring line width limitations. There
** are several flags that modify the default behavior of this function:
**
** COMMENT_PRINT_LEGACY: Forces use of the legacy comment printing
** algorithm. For backward compatibility,
** this is the default.
**
** COMMENT_PRINT_TRIM_CRLF: Trims leading and trailing carriage-returns
** and line-feeds where they do not materially
** impact pre-existing formatting (i.e. at the
** start of the comment string -AND- right
** before line indentation). This flag does
** not apply to the legacy comment printing
** algorithm. This flag may be combined with
** COMMENT_PRINT_TRIM_SPACE.
**
** COMMENT_PRINT_TRIM_SPACE: Trims leading and trailing spaces where they
** do not materially impact the pre-existing
** formatting (i.e. at the start of the comment
** string -AND- right before line indentation).
** This flag does not apply to the legacy
** comment printing algorithm. This flag may
** be combined with COMMENT_PRINT_TRIM_CRLF.
**
** COMMENT_PRINT_WORD_BREAK: Attempts to break lines on word boundaries
** while honoring the logical line length.
** If this flag is not specified, honoring the
** logical line length may result in breaking
** lines in the middle of words. This flag
** does not apply to the legacy comment
** printing algorithm.
**
** COMMENT_PRINT_ORIG_BREAK: Looks for the original comment text within
** the text being printed. Upon matching, a
** new line will be emitted, thus preserving
** more of the pre-existing formatting.
**
** Given a comment string, 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 'width' characters.
** Indent all subsequent lines by 'indent'.
**
** Returns the number of new lines emitted.
*/
int comment_print(
const char *zText, /* The comment text to be printed. */
const char *zOrigText, /* Original comment text ONLY, may be NULL. */
int indent, /* Spaces to indent each non-initial line. */
int width, /* Maximum number of characters per line. */
int flags /* Zero or more "COMMENT_PRINT_*" flags. */
){
int maxChars = width - indent;
int legacy = flags & COMMENT_PRINT_LEGACY;
int trimCrLf = flags & COMMENT_PRINT_TRIM_CRLF;
int trimSpace = flags & COMMENT_PRINT_TRIM_SPACE;
int wordBreak = flags & COMMENT_PRINT_WORD_BREAK;
int origBreak = flags & COMMENT_PRINT_ORIG_BREAK;
int lineCnt = 0;
const char *zLine;
if( legacy ){
return comment_print_legacy(zText, indent, width);
}
if( width<0 ){
comment_set_maxchars(indent, &maxChars);
}
if( zText==0 ) zText = "(NULL)";
if( maxChars<=0 ){
maxChars = strlen(zText);
}
if( trimSpace ){
while( fossil_isspace(zText[0]) ){ zText++; }
}
if( zText[0]==0 ){
fossil_print("\n");
lineCnt++;
return lineCnt;
}
zLine = zText;
for(;;){
comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0,
maxChars, trimCrLf, trimSpace, wordBreak, origBreak,
&lineCnt, &zLine);
if( !zLine || !zLine[0] ) break;
}
return lineCnt;
}
/*
**
** COMMAND: test-comment-format
**
** Usage: %fossil test-comment-format ?OPTIONS? PREFIX TEXT ?ORIGTEXT?
**
** Test comment formatting and printing. Use for testing only.
**
** Options:
** --file The comment text is really just a file name to
** read it from.
** --decode Decode the text using the same method used when
** handling the value of a C-card from a manifest.
** --legacy Use the legacy comment printing algorithm.
** --trimcrlf Enable trimming of leading/trailing CR/LF.
** --trimspace Enable trimming of leading/trailing spaces.
** --wordbreak Attempt to break lines on word boundaries.
** --origbreak Attempt to break when the original comment text
** is detected.
** --indent Number of spaces to indent (default (-1) is to
** auto-detect). Zero means no indent.
** -W|--width <num> Width of lines (default (-1) is to auto-detect).
** Zero means no limit.
*/
void test_comment_format(void){
const char *zWidth;
const char *zIndent;
const char *zPrefix;
char *zText;
char *zOrigText;
int indent, width;
int fromFile = find_option("file", 0, 0)!=0;
int decode = find_option("decode", 0, 0)!=0;
int flags = COMMENT_PRINT_NONE;
if( find_option("legacy", 0, 0) ){
flags |= COMMENT_PRINT_LEGACY;
}
if( find_option("trimcrlf", 0, 0) ){
flags |= COMMENT_PRINT_TRIM_CRLF;
}
if( find_option("trimspace", 0, 0) ){
flags |= COMMENT_PRINT_TRIM_SPACE;
}
if( find_option("wordbreak", 0, 0) ){
flags |= COMMENT_PRINT_WORD_BREAK;
}
if( find_option("origbreak", 0, 0) ){
flags |= COMMENT_PRINT_ORIG_BREAK;
}
zWidth = find_option("width","W",1);
if( zWidth ){
width = atoi(zWidth);
}else{
width = -1; /* automatic */
}
zIndent = find_option("indent",0,1);
if( zIndent ){
indent = atoi(zIndent);
}else{
indent = -1; /* automatic */
}
if( g.argc!=4 && g.argc!=5 ){
usage("?OPTIONS? PREFIX TEXT ?ORIGTEXT?");
}
zPrefix = g.argv[2];
zText = g.argv[3];
if( g.argc==5 ){
|
| ︙ | ︙ | |||
465 466 467 468 469 470 471 |
zText = mprintf(fromFile ? "%z" : "%s", zText);
defossilize(zText);
if( zOrigText ){
zOrigText = mprintf(fromFile ? "%z" : "%s", zOrigText);
defossilize(zOrigText);
}
}
| > | > | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 |
zText = mprintf(fromFile ? "%z" : "%s", zText);
defossilize(zText);
if( zOrigText ){
zOrigText = mprintf(fromFile ? "%z" : "%s", zOrigText);
defossilize(zOrigText);
}
}
if( indent<0 ){
indent = strlen(zPrefix);
}
if( zPrefix && *zPrefix ){
fossil_print("%s", zPrefix);
}
fossil_print("(%d lines output)\n",
comment_print(zText, zOrigText, indent, width, flags));
if( zOrigText && zOrigText!=g.argv[4] ) fossil_free(zOrigText);
if( zText && zText!=g.argv[3] ) fossil_free(zText);
}
|
Changes to src/db.c.
| ︙ | ︙ | |||
626 627 628 629 630 631 632 | /* ** Execute a query. Return the first column of the first row ** of the result set as a string. Space to hold the string is ** obtained from malloc(). If the result set is empty, return ** zDefault instead. */ | | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 |
/*
** Execute a query. Return the first column of the first row
** of the result set as a string. Space to hold the string is
** obtained from malloc(). If the result set is empty, return
** zDefault instead.
*/
char *db_text(const char *zDefault, const char *zSql, ...){
va_list ap;
Stmt s;
char *z;
va_start(ap, zSql);
db_vprepare(&s, 0, zSql, ap);
va_end(ap);
if( db_step(&s)==SQLITE_ROW ){
|
| ︙ | ︙ | |||
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 |
** option to locate the repository. If no such option is available, then
** use the repository of the open checkout if there is one.
**
** Error out if the repository cannot be opened.
*/
void db_find_and_open_repository(int bFlags, int nArgUsed){
const char *zRep = find_repository_option();
if( zRep==0 && nArgUsed && g.argc==nArgUsed+1 ){
zRep = g.argv[nArgUsed];
}
if( zRep==0 ){
if( db_open_local(0)==0 ){
goto rep_not_found;
}
| > > > | 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 |
** option to locate the repository. If no such option is available, then
** use the repository of the open checkout if there is one.
**
** Error out if the repository cannot be opened.
*/
void db_find_and_open_repository(int bFlags, int nArgUsed){
const char *zRep = find_repository_option();
if( zRep && file_isdir(zRep)==1 ){
goto rep_not_found;
}
if( zRep==0 && nArgUsed && g.argc==nArgUsed+1 ){
zRep = g.argv[nArgUsed];
}
if( zRep==0 ){
if( db_open_local(0)==0 ){
goto rep_not_found;
}
|
| ︙ | ︙ | |||
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 |
const char *zDate; /* Date of the initial check-in */
const char *zDefaultUser; /* Optional name of the default user */
zTemplate = find_option("template",0,1);
zDate = find_option("date-override",0,1);
zDefaultUser = find_option("admin-user","A",1);
find_option("empty", 0, 0); /* deprecated */
if( g.argc!=3 ){
usage("REPOSITORY-NAME");
}
db_create_repository(g.argv[2]);
db_open_repository(g.argv[2]);
db_open_config(0);
if( zTemplate ) db_attach(zTemplate, "settingSrc");
| > > > > | 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 |
const char *zDate; /* Date of the initial check-in */
const char *zDefaultUser; /* Optional name of the default user */
zTemplate = find_option("template",0,1);
zDate = find_option("date-override",0,1);
zDefaultUser = find_option("admin-user","A",1);
find_option("empty", 0, 0); /* deprecated */
/* We should be done with options.. */
verify_all_options();
if( g.argc!=3 ){
usage("REPOSITORY-NAME");
}
db_create_repository(g.argv[2]);
db_open_repository(g.argv[2]);
db_open_config(0);
if( zTemplate ) db_attach(zTemplate, "settingSrc");
|
| ︙ | ︙ | |||
1930 1931 1932 1933 1934 1935 1936 | } /* ** Returns non-0 if the database (which must be open) table identified ** by zTableName has a column named zColName (case-sensitive), else ** returns 0. */ | | | | 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 |
}
/*
** Returns non-0 if the database (which must be open) table identified
** by zTableName has a column named zColName (case-sensitive), else
** returns 0.
*/
int db_table_has_column(const char *zTableName, const char *zColName){
Stmt q = empty_Stmt;
int rc = 0;
db_prepare( &q, "PRAGMA table_info(%Q)", zTableName );
while(SQLITE_ROW == db_step(&q)){
/* Columns: (cid, name, type, notnull, dflt_value, pk) */
const char *zCol = db_column_text(&q, 1);
if( 0==fossil_strcmp(zColName, zCol) ){
rc = 1;
break;
}
}
db_finalize(&q);
return rc;
|
| ︙ | ︙ | |||
2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 |
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
url_proxy_options();
emptyFlag = find_option("empty",0,0)!=0;
keepFlag = find_option("keep",0,0)!=0;
forceMissingFlag = find_option("force-missing",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]);
| > > > > | 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 |
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
url_proxy_options();
emptyFlag = find_option("empty",0,0)!=0;
keepFlag = find_option("keep",0,0)!=0;
forceMissingFlag = find_option("force-missing",0,0)!=0;
allowNested = find_option("nested",0,0)!=0;
/* We should be done with options.. */
verify_all_options();
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]);
|
| ︙ | ︙ | |||
2131 2132 2133 2134 2135 2136 2137 |
** width is the length for the edit field on the behavior page, 0
** is used for on/off checkboxes.
** The behaviour page doesn't use a special layout. It lists all
** set-commands and displays the 'set'-help as info.
*/
#if INTERFACE
struct stControlSettings {
| | | | | 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 |
** width is the length for the edit field on the behavior page, 0
** is used for on/off checkboxes.
** The behaviour page doesn't use a special layout. It lists all
** set-commands and displays the 'set'-help as info.
*/
#if INTERFACE
struct stControlSettings {
const char *name; /* Name of the setting */
const char *var; /* Internal variable name used by db_set() */
int width; /* Width of display. 0 for boolean values. */
int versionable; /* Is this setting versionable? */
int forceTextArea; /* Force using a text area for display? */
const char *def; /* Default value */
};
#endif /* INTERFACE */
struct stControlSettings const ctrlSettings[] = {
{ "access-log", 0, 0, 0, 0, "off" },
{ "allow-symlinks", 0, 0, 1, 0, "off" },
{ "auto-captcha", "autocaptcha", 0, 0, 0, "on" },
{ "auto-hyperlink", 0, 0, 0, 0, "on", },
|
| ︙ | ︙ |
Changes to src/descendants.c.
| ︙ | ︙ | |||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
}
}
db_finalize(&ins);
db_finalize(&isBr);
db_finalize(&q1);
bag_clear(&pending);
bag_clear(&seen);
}
if( closeMode==1 ){
db_multi_exec(
"DELETE FROM leaves WHERE rid IN"
" (SELECT leaves.rid FROM leaves, tagxref"
" WHERE tagxref.rid=leaves.rid "
" AND tagxref.tagid=%d"
| > > > > > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
}
}
db_finalize(&ins);
db_finalize(&isBr);
db_finalize(&q1);
bag_clear(&pending);
bag_clear(&seen);
}else{
db_multi_exec(
"INSERT INTO leaves"
" SELECT leaf.rid FROM leaf"
);
}
if( closeMode==1 ){
db_multi_exec(
"DELETE FROM leaves WHERE rid IN"
" (SELECT leaves.rid FROM leaves, tagxref"
" WHERE tagxref.rid=leaves.rid "
" AND tagxref.tagid=%d"
|
| ︙ | ︙ | |||
310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("-W|--width value must be >20 or 0");
}
}else{
width = -1;
}
if( g.argc==2 ){
base = db_lget_int("checkout", 0);
}else{
base = name_to_typed_rid(g.argv[2], "ci");
}
if( base==0 ) return;
compute_leaves(base, 0);
| > > > > | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("-W|--width value must be >20 or 0");
}
}else{
width = -1;
}
/* We should be done with options.. */
verify_all_options();
if( g.argc==2 ){
base = db_lget_int("checkout", 0);
}else{
base = name_to_typed_rid(g.argv[2], "ci");
}
if( base==0 ) return;
compute_leaves(base, 0);
|
| ︙ | ︙ | |||
371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
if( (width!=0) && (width<=39) ){
fossil_fatal("-W|--width value must be >39 or 0");
}
}else{
width = -1;
}
db_find_and_open_repository(0,0);
if( recomputeFlag ) leaf_rebuild();
blob_zero(&sql);
blob_append(&sql, timeline_query_for_tty(), -1);
blob_appendf(&sql, " AND blob.rid IN leaf");
if( showClosed ){
blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
}else if( !showAll ){
| > > > > | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
if( (width!=0) && (width<=39) ){
fossil_fatal("-W|--width value must be >39 or 0");
}
}else{
width = -1;
}
db_find_and_open_repository(0,0);
/* We should be done with options.. */
verify_all_options();
if( recomputeFlag ) leaf_rebuild();
blob_zero(&sql);
blob_append(&sql, timeline_query_for_tty(), -1);
blob_appendf(&sql, " AND blob.rid IN leaf");
if( showClosed ){
blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
}else if( !showAll ){
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 |
annFlags = DIFF_IGNORE_EOLWS;
}
if( find_option("ignore-all-space","w",0)!=0 ){
annFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */
}
fileVers = find_option("filevers",0,0)!=0;
db_must_be_within_tree();
if( g.argc<3 ) {
usage("FILENAME");
}
file_tree_name(g.argv[2], &treename, 1);
zFilename = blob_str(&treename);
fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
if( fnid==0 ){
| > > > > | 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 |
annFlags = DIFF_IGNORE_EOLWS;
}
if( find_option("ignore-all-space","w",0)!=0 ){
annFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */
}
fileVers = find_option("filevers",0,0)!=0;
db_must_be_within_tree();
/* We should be done with options.. */
verify_all_options();
if( g.argc<3 ) {
usage("FILENAME");
}
file_tree_name(g.argv[2], &treename, 1);
zFilename = blob_str(&treename);
fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
if( fnid==0 ){
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
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);
| > > > | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
capture_case_sensitive_option();
db_must_be_within_tree();
if( find_option("status","s",0) ){
Stmt q;
Blob line;
Blob fname;
int vid;
/* We should be done with options.. */
verify_all_options();
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);
|
| ︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
fossil_print("%s\n", blob_str(&line));
blob_reset(&fname);
blob_reset(&line);
}else if( find_option("print","p",0) ){
Blob record;
Blob fname;
const char *zRevision = find_option("revision", "r", 1);
file_tree_name(g.argv[2], &fname, 1);
if( zRevision ){
historical_version_of_file(zRevision, blob_str(&fname), &record, 0,0,0,0);
}else{
int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s",
&fname, filename_collation());
| > > > | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
fossil_print("%s\n", blob_str(&line));
blob_reset(&fname);
blob_reset(&line);
}else if( find_option("print","p",0) ){
Blob record;
Blob fname;
const char *zRevision = find_option("revision", "r", 1);
/* We should be done with options.. */
verify_all_options();
file_tree_name(g.argv[2], &fname, 1);
if( zRevision ){
historical_version_of_file(zRevision, blob_str(&fname), &record, 0,0,0,0);
}else{
int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s",
&fname, filename_collation());
|
| ︙ | ︙ | |||
156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
iWidth = atoi(zWidth);
if( (iWidth!=0) && (iWidth<=22) ){
fossil_fatal("-W|--width value must be >22 or 0");
}
}else{
iWidth = -1;
}
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 ){
| > > > > | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
iWidth = atoi(zWidth);
if( (iWidth!=0) && (iWidth<=22) ){
fossil_fatal("-W|--width value must be >22 or 0");
}
}else{
iWidth = -1;
}
/* We should be done with options.. */
verify_all_options();
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 ){
|
| ︙ | ︙ | |||
197 198 199 200 201 202 203 |
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);
| | | | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
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 = mprintf(
"[%S] %s (user: %s, artifact: [%S], branch: %s)",
zCiUuid, zCom, zUser, zFileUuid, zBr);
comment_print(zOut, zCom, 11, iWidth, g.comFmtFlags);
fossil_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 );
|
| ︙ | ︙ | |||
239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
void cat_cmd(void){
int i;
int rc;
Blob content, fname;
const char *zRev;
db_find_and_open_repository(0, 0);
zRev = find_option("r","r",1);
for(i=2; i<g.argc; i++){
file_tree_name(g.argv[i], &fname, 1);
blob_zero(&content);
rc = historical_version_of_file(zRev, blob_str(&fname), &content, 0,0,0,0);
if( rc==0 ){
fossil_fatal("no such file: %s", g.argv[i]);
}
| > > > > | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
void cat_cmd(void){
int i;
int rc;
Blob content, fname;
const char *zRev;
db_find_and_open_repository(0, 0);
zRev = find_option("r","r",1);
/* We should be done with options.. */
verify_all_options();
for(i=2; i<g.argc; i++){
file_tree_name(g.argv[i], &fname, 1);
blob_zero(&content);
rc = historical_version_of_file(zRev, blob_str(&fname), &content, 0,0,0,0);
if( rc==0 ){
fossil_fatal("no such file: %s", g.argv[i]);
}
|
| ︙ | ︙ |
Changes to src/graph.c.
| ︙ | ︙ | |||
32 33 34 35 36 37 38 |
*/
struct GraphRow {
int rid; /* The rid for the check-in */
i8 nParent; /* Number of parents */
int *aParent; /* Array of parents. 0 element is primary .*/
char *zBranch; /* Branch name */
char *zBgClr; /* Background Color */
| | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
*/
struct GraphRow {
int rid; /* The rid for the check-in */
i8 nParent; /* Number of parents */
int *aParent; /* Array of parents. 0 element is primary .*/
char *zBranch; /* Branch name */
char *zBgClr; /* Background Color */
char zUuid[41]; /* Check-in for file ID */
GraphRow *pNext; /* Next row down in the list of all rows */
GraphRow *pPrev; /* Previous row */
int idx; /* Row index. First is 1. 0 used for "none" */
int idxTop; /* Direct descendent highest up on the graph */
GraphRow *pChild; /* Child immediately above this node */
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
*/
void info_cmd(void){
i64 fsize;
int verboseFlag = find_option("verbose","v",0)!=0;
if( !verboseFlag ){
verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
}
if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
db_open_config(0);
db_record_repository_filename(g.argv[2]);
db_open_repository(g.argv[2]);
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
extraRepoInfo();
| > > > > | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
*/
void info_cmd(void){
i64 fsize;
int verboseFlag = find_option("verbose","v",0)!=0;
if( !verboseFlag ){
verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
}
/* We should be done with options.. */
verify_all_options();
if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
db_open_config(0);
db_record_repository_filename(g.argv[2]);
db_open_repository(g.argv[2]);
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
extraRepoInfo();
|
| ︙ | ︙ | |||
985 986 987 988 989 990 991 992 993 994 995 996 997 998 |
zFrom = P("from");
zTo = P("to");
if(zGlob && !*zGlob){
zGlob = NULL;
}
diffFlags = construct_diff_flags(verboseFlag, sideBySide);
zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
if( sideBySide || verboseFlag ){
style_submenu_element("Hide Diff", "hidediff",
"%R/vdiff?from=%T&to=%T&sbs=0%s%T%s",
zFrom, zTo,
zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW);
}
if( !sideBySide ){
| > > | 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 |
zFrom = P("from");
zTo = P("to");
if(zGlob && !*zGlob){
zGlob = NULL;
}
diffFlags = construct_diff_flags(verboseFlag, sideBySide);
zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
style_submenu_element("Path","path",
"%R/timeline?me=%T&you=%T", zFrom, zTo);
if( sideBySide || verboseFlag ){
style_submenu_element("Hide Diff", "hidediff",
"%R/vdiff?from=%T&to=%T&sbs=0%s%T%s",
zFrom, zTo,
zGlob ? "&glob=" : "", zGlob ? zGlob : "", zW);
}
if( !sideBySide ){
|
| ︙ | ︙ | |||
2098 2099 2100 2101 2102 2103 2104 |
@ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)"
@ checked="checked" onclick="gebi('%s(zIdCustom)').select();" />
}
@ %h(aColor[i].zCName)</label>
@ <input type="text" name="%s(zIdCustom)"
@ id="%s(zIdCustom)" class="checkinUserColor"
@ value="%h(stdClrFound?"":zDefaultColor)"
| | > > | 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 |
@ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)"
@ checked="checked" onclick="gebi('%s(zIdCustom)').select();" />
}
@ %h(aColor[i].zCName)</label>
@ <input type="text" name="%s(zIdCustom)"
@ id="%s(zIdCustom)" class="checkinUserColor"
@ value="%h(stdClrFound?"":zDefaultColor)"
@ onfocus="this.form.elements['%s(zId)'][%d(nColor)].checked = true;"
@ onload="this.blur();"
@ onblur="this.parentElement.style.backgroundColor = this.value ? ('#'+this.value.replace('#','')) : '';" />
@ </td>
@ </tr>
@ </table>
}
/*
** Do a comment comparison.
|
| ︙ | ︙ |
Changes to src/login.c.
| ︙ | ︙ | |||
206 207 208 209 210 211 212 | ** Searches for the user ID matching the given name and password. ** On success it returns a positive value. On error it returns 0. ** On serious (DB-level) error it will probably exit. ** ** zPassword may be either the plain-text form or the encrypted ** form of the user's password. */ | | | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
** Searches for the user ID matching the given name and password.
** On success it returns a positive value. On error it returns 0.
** On serious (DB-level) error it will probably exit.
**
** zPassword may be either the plain-text form or the encrypted
** form of the user's password.
*/
int login_search_uid(const char *zUsername, const char *zPasswd){
char *zSha1Pw = sha1_shared_secret(zPasswd, zUsername, 0);
int const uid =
db_int(0,
"SELECT uid FROM user"
" WHERE login=%Q"
" AND length(cap)>0 AND length(pw)>0"
" AND login NOT IN ('anonymous','nobody','developer','reader')"
" AND (pw=%Q OR (length(pw)<>40 AND pw=%Q))",
|
| ︙ | ︙ | |||
229 230 231 232 233 234 235 | ** Generates a login cookie value for a non-anonymous user. ** ** The zHash parameter must be a random value which must be ** subsequently stored in user.cookie for later validation. ** ** The returned memory should be free()d after use. */ | | | | | | | 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 |
** Generates a login cookie value for a non-anonymous user.
**
** The zHash parameter must be a random value which must be
** subsequently stored in user.cookie for later validation.
**
** The returned memory should be free()d after use.
*/
char *login_gen_user_cookie_value(const char *zUsername, const char *zHash){
char *zProjCode = db_get("project-code",NULL);
char *zCode = abbreviated_project_code(zProjCode);
free(zProjCode);
assert((zUsername && *zUsername) && "Invalid user data.");
return mprintf("%s/%z/%s", zHash, zCode, zUsername);
}
/*
** Generates a login cookie for NON-ANONYMOUS users. Note that this
** function "could" figure out the uid by itself but it currently
** doesn't because the code which calls this already has the uid.
**
** This function also updates the user.cookie, user.ipaddr,
** and user.cexpire fields for the given user.
**
** If zDest is not NULL then the generated cookie is copied to
** *zDdest and ownership is transfered to the caller (who should
** eventually pass it to free()).
*/
void login_set_user_cookie(
const char *zUsername, /* User's name */
int uid, /* User's ID */
char **zDest /* Optional: store generated cookie value. */
){
const char *zCookieName = login_cookie_name();
const char *zExpire = db_get("cookie-expire","8766");
int expires = atoi(zExpire)*3600;
char *zHash;
char *zCookie;
const char *zIpAddr = PD("REMOTE_ADDR","nil"); /* IP address of user */
char *zRemoteAddr = ipPrefix(zIpAddr); /* Abbreviated IP address */
assert((zUsername && *zUsername) && (uid > 0) && "Invalid user data.");
zHash = db_text(0,
"SELECT cookie FROM user"
" WHERE uid=%d"
" AND ipaddr=%Q"
|
| ︙ | ︙ | |||
301 302 303 304 305 306 307 | ** ** If either zIpAddr or zRemoteAddr are NULL then REMOTE_ADDR ** is used. ** ** If zCookieDest is not NULL then the generated cookie is assigned to ** *zCookieDest and the caller must eventually free() it. */ | | | | | | 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
**
** If either zIpAddr or zRemoteAddr are NULL then REMOTE_ADDR
** is used.
**
** If zCookieDest is not NULL then the generated cookie is assigned to
** *zCookieDest and the caller must eventually free() it.
*/
void login_set_anon_cookie(const char *zIpAddr, char **zCookieDest ){
const char *zNow; /* Current time (julian day number) */
char *zCookie; /* The login cookie */
const char *zCookieName; /* Name of the login cookie */
Blob b; /* Blob used during cookie construction */
char *zRemoteAddr; /* Abbreviated IP address */
if(!zIpAddr){
zIpAddr = PD("REMOTE_ADDR","nil");
}
zRemoteAddr = ipPrefix(zIpAddr);
zCookieName = login_cookie_name();
zNow = db_text("0", "SELECT julianday('now')");
assert( zCookieName && zRemoteAddr && zIpAddr && zNow );
|
| ︙ | ︙ | |||
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{
const char *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);
|
| ︙ | ︙ | |||
627 628 629 630 631 632 633 |
@ 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();
| | | 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
@ 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();
const char *zDecoded = captcha_decode(uSeed);
int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
char *zCaptcha = captcha_render(zDecoded);
@ <p><input type="hidden" name="cs" value="%u(uSeed)" />
@ Visitors may enter <b>anonymous</b> as the user-ID with
@ the 8-character hexadecimal password shown below:</p>
@ <div class="captcha"><table class="captcha"><tr><td><pre>
|
| ︙ | ︙ | |||
1234 1235 1236 1237 1238 1239 1240 |
**
** Generate the register page.
**
*/
void register_page(void){
const char *zUsername, *zPasswd, *zConfirm, *zContact, *zCS, *zPw, *zCap;
unsigned int uSeed;
| | | 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 |
**
** Generate the register page.
**
*/
void register_page(void){
const char *zUsername, *zPasswd, *zConfirm, *zContact, *zCS, *zPw, *zCap;
unsigned int uSeed;
const char *zDecoded;
char *zCaptcha;
if( !db_get_boolean("self-register", 0) ){
style_header("Registration not possible");
@ <p>This project does not allow user self-registration. Please contact the
@ project administrator to obtain an account.</p>
style_footer();
return;
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
227 228 229 230 231 232 233 |
responses and always exit() with
code 0 to avoid an HTTP 500 error.
*/
int resultCode; /* used for passing back specific codes
** from /json callbacks. */
int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
cson_output_opt outOpt; /* formatting options for JSON mode. */
| | | | | | | | | | | | | | | | 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 |
responses and always exit() with
code 0 to avoid an HTTP 500 error.
*/
int resultCode; /* used for passing back specific codes
** from /json callbacks. */
int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
cson_output_opt outOpt; /* formatting options for JSON mode. */
cson_value *authToken; /* authentication token */
const char *jsonp; /* Name of JSONP function wrapper. */
unsigned char dispatchDepth /* Tells JSON command dispatching
which argument we are currently
working on. For this purpose, arg#0
is the "json" path/CLI arg.
*/;
struct { /* "garbage collector" */
cson_value *v;
cson_array *a;
} gc;
struct { /* JSON POST data. */
cson_value *v;
cson_array *a;
int offset; /* Tells us which PATH_INFO/CLI args
part holds the "json" command, so
that we can account for sub-repos
and path prefixes. This is handled
differently for CLI and CGI modes.
*/
const char *commandStr /*"command" request param.*/;
} cmd;
struct { /* JSON POST data. */
cson_value *v;
cson_object *o;
} post;
struct { /* GET/COOKIE params in JSON mode. */
cson_value *v;
cson_object *o;
} param;
struct {
cson_value *v;
cson_object *o;
} reqPayload; /* request payload object (if any) */
cson_array *warnings; /* response warnings */
int timerId; /* fetched from fossil_timer_start() */
} json;
#endif /* FOSSIL_ENABLE_JSON */
};
/*
** Macro for debugging:
|
| ︙ | ︙ | |||
389 390 391 392 393 394 395 | Blob file = empty_blob; /* Content of the file */ 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 */ | | | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | Blob file = empty_blob; /* Content of the file */ 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 */ const char *zFileName; /* input file name */ FILE *inFile; /* input FILE */ #if defined(_WIN32) wchar_t buf[MAX_PATH]; #endif g.argc = argc; g.argv = argv; |
| ︙ | ︙ | |||
934 935 936 937 938 939 940 941 |
**
** 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());
| > > | > > > > > | 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 |
**
** 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){
int verboseFlag = 0;
fossil_print("This is fossil version %s\n", get_version());
verboseFlag = find_option("verbose","v",0)!=0;
/* We should be done with options.. */
verify_all_options();
if(!verboseFlag){
return;
}else{
#if defined(FOSSIL_ENABLE_TCL)
int rc;
const char *zRc;
#endif
fossil_print("Compiled on %s %s using %s (%d-bit)\n",
|
| ︙ | ︙ | |||
995 996 997 998 999 1000 1001 |
** %fossil help --t|-test Show test commands only
** %fossil help --x|-aux Show auxiliary commands only
** %fossil help --w|-www Show list of WWW pages
*/
void help_cmd(void){
int rc, idx, isPage = 0;
const char *z;
| | | | 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 |
** %fossil help --t|-test Show test commands only
** %fossil help --x|-aux Show auxiliary commands only
** %fossil help --w|-www Show list of WWW pages
*/
void help_cmd(void){
int rc, idx, isPage = 0;
const char *z;
const char *zCmdOrPage;
const char *zCmdOrPagePlural;
if( g.argc<3 ){
z = g.argv[0];
fossil_print(
"Usage: %s help COMMAND\n"
"Common COMMANDs: (use \"%s help -a|--all\" for a complete list)\n",
z, z);
command_list(0, CMDFLAG_1ST_TIER);
|
| ︙ | ︙ | |||
1065 1066 1067 1068 1069 1070 1071 |
}
/*
** WEBPAGE: help
** URL: /help/CMD
*/
void help_page(void){
| | | | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 |
}
/*
** WEBPAGE: help
** URL: /help/CMD
*/
void help_page(void){
const char *zCmd = P("cmd");
if( zCmd==0 ) zCmd = P("name");
style_header("Command-line Help");
if( zCmd ){
int rc, idx;
char *z, *s, *d;
const char *zCmdOrPage = ('/'==*zCmd) ? "page" : "command";
style_submenu_element("Command-List", "Command-List", "%s/help", g.zTop);
@ <h1>The "%s(zCmd)" %s(zCmdOrPage):</h1>
rc = name_search(zCmd, aCommand, count(aCommand), 0, &idx);
if( rc==1 ){
@ unknown command: %s(zCmd)
}else if( rc==2 ){
@ ambiguous command prefix: %s(zCmd)
|
| ︙ | ︙ | |||
1408 1409 1410 1411 1412 1413 1414 |
szFile = 1;
break;
}
if( szFile==0 ){
if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; }
szFile = file_size(zRepo);
}
| | | 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 |
szFile = 1;
break;
}
if( szFile==0 ){
if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; }
szFile = file_size(zRepo);
}
if( szFile<0 && i>0 ){
const char *zMimetype;
assert( fossil_strcmp(&zRepo[j], ".fossil")==0 );
zRepo[j] = 0;
if( zPathInfo[i]=='/' && file_isdir(zRepo)==1 ){
fossil_free(zToFree);
i++;
continue;
|
| ︙ | ︙ | |||
1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 |
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");
| > > > > | 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 |
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;
/* We should be done with options.. */
verify_all_options();
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");
|
| ︙ | ︙ | |||
2092 2093 2094 2095 2096 2097 2098 |
char *zIpAddr = 0; /* Bind to this IP address */
#if defined(_WIN32)
const char *zStopperFile; /* Name of file used to terminate server */
zStopperFile = find_option("stopper", 0, 1);
#endif
| | > > > > > > > | > > > > | 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 |
char *zIpAddr = 0; /* Bind to this IP address */
#if defined(_WIN32)
const char *zStopperFile; /* Name of file used to terminate server */
zStopperFile = find_option("stopper", 0, 1);
#endif
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);
}
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;
}
/* We should be done with options.. */
verify_all_options();
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);
|
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
383 384 385 386 387 388 389 | 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. | > | | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
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 = -DNDEBUG=1 \
-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.
|
| ︙ | ︙ |
Changes to src/makemake.tcl.
| ︙ | ︙ | |||
130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
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
}
| > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
zip
http_ssl
}
# Options used to compile the included SQLite library.
#
set SQLITE_OPTIONS {
-DNDEBUG=1
-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
}
|
| ︙ | ︙ | |||
453 454 455 456 457 458 459 | 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. # | | | | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | 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.1i/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1i #### 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 |
| ︙ | ︙ | |||
824 825 826 827 828 829 830 |
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"
}
| > > > | | 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 |
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 SQLITE_WIN32_OPTIONS $SQLITE_OPTIONS
lappend SQLITE_WIN32_OPTIONS -DSQLITE_WIN32_NO_ANSI
set MINGW_SQLITE_OPTIONS $SQLITE_WIN32_OPTIONS
lappend MINGW_SQLITE_OPTIONS -D_HAVE__MINGW_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 "
|
| ︙ | ︙ | |||
1051 1052 1053 1054 1055 1056 1057 | # Uncomment to enable TH1 hooks # FOSSIL_ENABLE_TH1_HOOKS = 1 # Uncomment to enable Tcl support # FOSSIL_ENABLE_TCL = 1 !ifdef FOSSIL_ENABLE_SSL | | | | 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 | # Uncomment to enable TH1 hooks # FOSSIL_ENABLE_TH1_HOOKS = 1 # Uncomment to enable Tcl support # FOSSIL_ENABLE_TCL = 1 !ifdef FOSSIL_ENABLE_SSL SSLINCDIR = $(B)\compat\openssl-1.0.1i\include SSLLIBDIR = $(B)\compat\openssl-1.0.1i\out32 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib !endif !ifdef FOSSIL_ENABLE_TCL TCLDIR = $(B)\compat\tcl-8.6 TCLSRCDIR = $(TCLDIR) TCLINCDIR = $(TCLSRCDIR)\generic |
| ︙ | ︙ | |||
1121 1122 1123 1124 1125 1126 1127 | RCC = $(RCC) /DFOSSIL_ENABLE_TCL_STUBS=1 TCC = $(TCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 RCC = $(RCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 TCC = $(TCC) /DUSE_TCL_STUBS=1 RCC = $(RCC) /DUSE_TCL_STUBS=1 !endif } | | | 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 |
RCC = $(RCC) /DFOSSIL_ENABLE_TCL_STUBS=1
TCC = $(TCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1
RCC = $(RCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1
TCC = $(TCC) /DUSE_TCL_STUBS=1
RCC = $(RCC) /DUSE_TCL_STUBS=1
!endif
}
regsub -all {[-]D} [join $SQLITE_WIN32_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"
|
| ︙ | ︙ | |||
1292 1293 1294 1295 1296 1297 1298 | # 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 \ | | | 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 |
# 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_WIN32_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"
|
| ︙ | ︙ |
Changes to src/merge.c.
| ︙ | ︙ | |||
642 643 644 645 646 647 648 |
}
if( nOverwrite ){
fossil_warning("WARNING: %d unmanaged files were overwritten",
nOverwrite);
}
if( dryRunFlag ){
fossil_warning("REMINDER: this was a dry run -"
| | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 |
}
if( nOverwrite ){
fossil_warning("WARNING: %d unmanaged files were overwritten",
nOverwrite);
}
if( dryRunFlag ){
fossil_warning("REMINDER: this was a dry run -"
" no files were actually changed.");
}
/*
** Clean up the mid and pid VFILE entries. Then commit the changes.
*/
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
if( pickFlag ){
|
| ︙ | ︙ |
Changes to src/merge3.c.
| ︙ | ︙ | |||
134 135 136 137 138 139 140 | } return i; } /* ** Text of boundary markers for merge conflicts. */ | | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
}
return i;
}
/*
** Text of boundary markers for merge conflicts.
*/
static const char *const mergeMarker[] = {
/*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
"<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<\n",
"======= COMMON ANCESTOR content follows ============================\n",
"======= MERGED IN content follows ==================================\n",
">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
};
|
| ︙ | ︙ | |||
366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
** 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 ){
fossil_fatal("cannot read %s\n", g.argv[2]);
}
if( blob_read_from_file(&v1, g.argv[3])<0 ){
| > > > > | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
** cp Xup.c Xbase.c
** # Verify that everything still works
** fossil commit
**
*/
void delta_3waymerge_cmd(void){
Blob pivot, v1, v2, merged;
/* We should be done with options.. */
verify_all_options();
if( g.argc!=6 ){
usage("PIVOT V1 V2 MERGED");
}
if( blob_read_from_file(&pivot, g.argv[2])<0 ){
fossil_fatal("cannot read %s\n", g.argv[2]);
}
if( blob_read_from_file(&v1, g.argv[3])<0 ){
|
| ︙ | ︙ |
Changes to src/name.c.
| ︙ | ︙ | |||
657 658 659 660 661 662 663 664 665 666 667 668 669 670 |
void whatis_cmd(void){
int rid;
const char *zName;
int verboseFlag;
int i;
db_find_and_open_repository(0,0);
verboseFlag = find_option("verbose","v",0)!=0;
if( g.argc<3 ) usage("whatis NAME ...");
for(i=2; i<g.argc; i++){
zName = g.argv[i];
if( i>2 ) fossil_print("%.79c\n",'-');
rid = symbolic_name_to_rid(zName, 0);
if( rid<0 ){
Stmt q;
| > > > > | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 |
void whatis_cmd(void){
int rid;
const char *zName;
int verboseFlag;
int i;
db_find_and_open_repository(0,0);
verboseFlag = find_option("verbose","v",0)!=0;
/* We should be done with options.. */
verify_all_options();
if( g.argc<3 ) usage("whatis NAME ...");
for(i=2; i<g.argc; i++){
zName = g.argv[i];
if( i>2 ) fossil_print("%.79c\n",'-');
rid = symbolic_name_to_rid(zName, 0);
if( rid<0 ){
Stmt q;
|
| ︙ | ︙ |
Changes to src/rebuild.c.
| ︙ | ︙ | |||
576 577 578 579 580 581 582 583 584 585 586 587 588 589 |
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
if( g.argc!=2 ){
usage("?REPOSITORY-FILENAME?");
}
db_close(1);
db_open_repository(g.zRepositoryName);
}
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());"
| > > > > | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
if( g.argc!=2 ){
usage("?REPOSITORY-FILENAME?");
}
db_close(1);
db_open_repository(g.zRepositoryName);
}
/* We should be done with options.. */
verify_all_options();
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());"
|
| ︙ | ︙ | |||
791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
int bVerily = find_option("verily",0,0)!=0;
int bForce = find_option("force", "f", 0)!=0;
int privateOnly = find_option("private",0,0)!=0;
int bNeedRebuild = 0;
db_find_and_open_repository(OPEN_ANY_SCHEMA, 2);
db_close(1);
db_open_repository(g.zRepositoryName);
if( !bForce ){
Blob ans;
char cReply;
prompt_user(
"Scrubbing the repository will permanently delete information.\n"
"Changes cannot be undone. Continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
| > > > > | 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 |
int bVerily = find_option("verily",0,0)!=0;
int bForce = find_option("force", "f", 0)!=0;
int privateOnly = find_option("private",0,0)!=0;
int bNeedRebuild = 0;
db_find_and_open_repository(OPEN_ANY_SCHEMA, 2);
db_close(1);
db_open_repository(g.zRepositoryName);
/* We should be done with options.. */
verify_all_options();
if( !bForce ){
Blob ans;
char cReply;
prompt_user(
"Scrubbing the repository will permanently delete information.\n"
"Changes cannot be undone. Continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
|
| ︙ | ︙ | |||
913 914 915 916 917 918 919 920 921 922 923 924 925 926 |
}
if( file_isdir(g.argv[3])!=1 ){
fossil_print("\"%s\" is not a directory\n\n", g.argv[3]);
usage("FILENAME DIRECTORY");
}
db_create_repository(g.argv[2]);
db_open_repository(g.argv[2]);
db_open_config(0);
db_begin_transaction();
db_initial_setup(0, 0, 0, 1);
fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]);
recon_read_dir(g.argv[3]);
fossil_print("\nBuilding the Fossil repository...\n");
| > > > > | 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 |
}
if( file_isdir(g.argv[3])!=1 ){
fossil_print("\"%s\" is not a directory\n\n", g.argv[3]);
usage("FILENAME DIRECTORY");
}
db_create_repository(g.argv[2]);
db_open_repository(g.argv[2]);
/* We should be done with options.. */
verify_all_options();
db_open_config(0);
db_begin_transaction();
db_initial_setup(0, 0, 0, 1);
fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]);
recon_read_dir(g.argv[3]);
fossil_print("\nBuilding the Fossil repository...\n");
|
| ︙ | ︙ |
Changes to src/regexp.c.
| ︙ | ︙ | |||
766 767 768 769 770 771 772 |
**
** -i|--ignore-case Ignore case
*/
void re_test_grep(void){
ReCompiled *pRe;
const char *zErr;
int ignoreCase = find_option("ignore-case","i",0)!=0;
| < | 766 767 768 769 770 771 772 773 774 775 776 777 778 779 |
**
** -i|--ignore-case Ignore case
*/
void re_test_grep(void){
ReCompiled *pRe;
const char *zErr;
int ignoreCase = find_option("ignore-case","i",0)!=0;
if( g.argc<3 ){
usage("REGEXP [FILE...]");
}
zErr = re_compile(&pRe, g.argv[2], ignoreCase);
if( zErr ) fossil_fatal("%s", zErr);
if( g.argc==3 ){
grep(pRe, "-", stdin);
|
| ︙ | ︙ |
Changes to src/report.c.
| ︙ | ︙ | |||
1110 1111 1112 1113 1114 1115 1116 |
/*
** show all reports, which can be used for ticket show.
** Output is written to stdout as tab delimited table
*/
void rpt_list_reports(void){
Stmt q;
| | | 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 |
/*
** show all reports, which can be used for ticket show.
** Output is written to stdout as tab delimited table
*/
void rpt_list_reports(void){
Stmt q;
const char aRptOutFrmt[] = "%s\t%s\n";
fossil_print("Available reports:\n");
fossil_print(aRptOutFrmt,"report number","report title");
fossil_print(aRptOutFrmt,zFullTicketRptRn,zFullTicketRptTitle);
db_prepare(&q,"SELECT rn,title FROM reportfmt ORDER BY rn");
while( db_step(&q)==SQLITE_ROW ){
const char *zRn = db_column_text(&q, 0);
|
| ︙ | ︙ | |||
1215 1216 1217 1218 1219 1220 1221 | Stmt q; char *zSql; char *zErr1 = 0; char *zErr2 = 0; int count = 0; int rn; | | | 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 |
Stmt q;
char *zSql;
char *zErr1 = 0;
char *zErr2 = 0;
int count = 0;
int rn;
if( !zRep || !strcmp(zRep,zFullTicketRptRn) || !strcmp(zRep,zFullTicketRptTitle) ){
zSql = "SELECT * FROM ticket";
}else{
rn = atoi(zRep);
if( rn ){
db_prepare(&q,
"SELECT sqlcode FROM reportfmt WHERE rn=%d", rn);
}else{
|
| ︙ | ︙ |
Changes to src/rss.c.
| ︙ | ︙ | |||
25 26 27 28 29 30 31 | /* ** WEBPAGE: timeline.rss ** URL: /timeline.rss?y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME ** ** Produce an RSS feed of the timeline. ** ** TYPE may be: all, ci (show checkins only), t (show tickets only), | | > > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | /* ** WEBPAGE: timeline.rss ** URL: /timeline.rss?y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME ** ** Produce an RSS feed of the timeline. ** ** TYPE may be: all, 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, and wiki=NAME for a wiki page. Only one may be used. ** ** In addition, name=FILENAME filters for a specific file. This may be ** combined with one of the other filters (useful for looking at a specific ** branch). |
| ︙ | ︙ | |||
210 211 212 213 214 215 216 | ** Usage: %fossil rss ?OPTIONS? ** ** 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), | | > > > | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | ** Usage: %fossil rss ?OPTIONS? ** ** 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|n LIMIT ** The maximum number of items to show. ** ** -tkt UUID ** Filters for only those events for the specified ticket. ** ** -tag TAG ** filters for a tag ** |
| ︙ | ︙ | |||
265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
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);
}
| > > > | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
zType = "all";
}
if(!zBaseURL || !*zBaseURL){
zBaseURL = "URL-PLACEHOLDER";
}
db_find_and_open_repository(0, 0);
/* We should be done with options.. */
verify_all_options();
blob_zero(&bSQL);
blob_append( &bSQL, zSQL1, -1 );
if( zType[0]!='a' ){
blob_appendf(&bSQL, " AND event.type=%Q", zType);
}
|
| ︙ | ︙ |
Changes to src/shell.c.
| ︙ | ︙ | |||
60 61 62 63 64 65 66 67 68 69 70 71 72 73 | # 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) #ifndef access # define access(f,m) _access((f),(m)) #endif #undef popen #define popen _popen #undef pclose | > | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | # define read_history(X) # define write_history(X) # define stifle_history(X) #endif #if defined(_WIN32) || defined(WIN32) # include <io.h> # include <fcntl.h> #define isatty(h) _isatty(h) #ifndef access # define access(f,m) _access((f),(m)) #endif #undef popen #define popen _popen #undef pclose |
| ︙ | ︙ | |||
454 455 456 457 458 459 460 461 462 463 464 465 466 467 |
FILE *traceOut; /* Output for sqlite3_trace() */
int nErr; /* Number of errors seen */
int mode; /* An output mode setting */
int writableSchema; /* True if PRAGMA writable_schema=ON */
int showHeader; /* True to show column names in List or Column mode */
char *zDestTable; /* Name of destination table when MODE_Insert */
char separator[20]; /* Separator character for MODE_List */
int colWidth[100]; /* Requested width of each column when in column mode*/
int actualWidth[100]; /* Actual width of each column */
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 */
| > | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 |
FILE *traceOut; /* Output for sqlite3_trace() */
int nErr; /* Number of errors seen */
int mode; /* An output mode setting */
int writableSchema; /* True if PRAGMA writable_schema=ON */
int showHeader; /* True to show column names in List or Column mode */
char *zDestTable; /* Name of destination table when MODE_Insert */
char separator[20]; /* Separator character for MODE_List */
char newline[20]; /* Record separator in MODE_Csv */
int colWidth[100]; /* Requested width of each column when in column mode*/
int actualWidth[100]; /* Actual width of each column */
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 */
|
| ︙ | ︙ | |||
655 656 657 658 659 660 661 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; /* ** Output a single term of CSV. Actually, p->separator is used for ** the separator, which may or may not be a comma. p->nullvalue is | | > | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
/*
** Output a single term of CSV. Actually, p->separator is used for
** the separator, which may or may not be a comma. p->nullvalue is
** the null value. Strings are quoted if necessary. The separator
** is only issued if bSep is true.
*/
static void output_csv(struct callback_data *p, const char *z, int bSep){
FILE *out = p->out;
if( z==0 ){
fprintf(out,"%s",p->nullvalue);
}else{
int i;
|
| ︙ | ︙ | |||
851 852 853 854 855 856 857 858 859 860 861 |
output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
if(i<nArg-1) fprintf(p->out, "%s", p->separator);
}
fprintf(p->out,"\n");
break;
}
case MODE_Csv: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
}
| > > > > | | | | | | > > > > > | 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 |
output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
if(i<nArg-1) fprintf(p->out, "%s", p->separator);
}
fprintf(p->out,"\n");
break;
}
case MODE_Csv: {
#if defined(WIN32) || defined(_WIN32)
fflush(p->out);
_setmode(_fileno(p->out), _O_BINARY);
#endif
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
}
fprintf(p->out,"%s",p->newline);
}
if( azArg>0 ){
for(i=0; i<nArg; i++){
output_csv(p, azArg[i], i<nArg-1);
}
fprintf(p->out,"%s",p->newline);
}
#if defined(WIN32) || defined(_WIN32)
fflush(p->out);
_setmode(_fileno(p->out), _O_TEXT);
#endif
break;
}
case MODE_Insert: {
p->cnt++;
if( azArg==0 ) break;
fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
for(i=0; i<nArg; i++){
|
| ︙ | ︙ | |||
1615 1616 1617 1618 1619 1620 1621 | ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".save FILE Write in-memory database into FILE\n" ".schema ?TABLE? Show the CREATE statements\n" " If TABLE specified, only show tables matching\n" " LIKE pattern TABLE.\n" | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
".quit Exit this program\n"
".read FILENAME Execute SQL in FILENAME\n"
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
".save FILE Write in-memory database into FILE\n"
".schema ?TABLE? Show the CREATE statements\n"
" If TABLE specified, only show tables matching\n"
" LIKE pattern TABLE.\n"
".separator STRING ?NL? Change separator used by output mode and .import\n"
" NL is the end-of-line mark for CSV\n"
".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
".show Show the current values for various settings\n"
".stats on|off Turn stats on or off\n"
".system CMD ARGS... Run CMD ARGS... in a system shell\n"
".tables ?TABLE? List names of tables\n"
" If TABLE specified, only list tables matching\n"
" LIKE pattern TABLE.\n"
".timeout MS Try opening locked tables for MS milliseconds\n"
".timer on|off Turn SQL timer on or off\n"
".trace FILE|off Output each SQL statement as it is run\n"
".vfsname ?AUX? Print the name of the VFS stack\n"
".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
" Negative values right-justify\n"
;
/* Forward reference */
static int process_input(struct callback_data *p, FILE *in);
/*
** Implementation of the "readfile(X)" SQL function. The entire content
** of the file named X is read and returned as a BLOB. NULL is returned
** if the file does not exist or is unreadable.
*/
static void readfileFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zName;
FILE *in;
long nIn;
void *pBuf;
zName = (const char*)sqlite3_value_text(argv[0]);
if( zName==0 ) return;
in = fopen(zName, "rb");
if( in==0 ) return;
fseek(in, 0, SEEK_END);
nIn = ftell(in);
rewind(in);
pBuf = sqlite3_malloc( nIn );
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
}else{
sqlite3_free(pBuf);
}
fclose(in);
}
/*
** Implementation of the "writefile(X,Y)" SQL function. The argument Y
** is written into file X. The number of bytes written is returned. Or
** NULL is returned if something goes wrong, such as being unable to open
** file X for writing.
*/
static void writefileFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
FILE *out;
const char *z;
sqlite3_int64 rc;
const char *zFile;
zFile = (const char*)sqlite3_value_text(argv[0]);
if( zFile==0 ) return;
out = fopen(zFile, "wb");
if( out==0 ) return;
z = (const char*)sqlite3_value_blob(argv[1]);
if( z==0 ){
rc = 0;
}else{
rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
}
fclose(out);
sqlite3_result_int64(context, rc);
}
/*
** 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 ){
|
| ︙ | ︙ | |||
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 |
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
| > > > > | 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 |
p->zDbFilename, sqlite3_errmsg(db));
if( keepAlive ) return;
exit(1);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
readfileFunc, 0, 0);
sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
writefileFunc, 0, 0);
}
}
/*
** Do C-language style dequoting.
**
** \t -> tab
|
| ︙ | ︙ | |||
2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 |
p->mode = MODE_Html;
}else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
p->mode = MODE_Tcl;
sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
}else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
p->mode = MODE_Csv;
sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
}else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
}else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, nArg>=3 ? azArg[2] : "table");
}else {
| > | 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 |
p->mode = MODE_Html;
}else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
p->mode = MODE_Tcl;
sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
}else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
p->mode = MODE_Csv;
sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
sqlite3_snprintf(sizeof(p->newline), p->newline, "\r\n");
}else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
}else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, nArg>=3 ? azArg[2] : "table");
}else {
|
| ︙ | ︙ | |||
3025 3026 3027 3028 3029 3030 3031 |
fprintf(p->out, "%s", zBuf);
}
}
}else
#endif
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
| | < < < | > > > > > > | | > | 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 |
fprintf(p->out, "%s", zBuf);
}
}
}else
#endif
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
if( nArg<2 || nArg>3 ){
fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n");
rc = 1;
}
if( nArg>=2 ){
sqlite3_snprintf(sizeof(p->separator), p->separator, azArg[1]);
}
if( nArg>=3 ){
sqlite3_snprintf(sizeof(p->newline), p->newline, azArg[2]);
}
}else
if( c=='s'
&& (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
){
char *zCmd;
int i, x;
if( nArg<2 ){
fprintf(stderr, "Usage: .system COMMAND\n");
rc = 1;
goto meta_command_exit;
}
zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
for(i=2; i<nArg; i++){
zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
zCmd, azArg[i]);
}
x = system(zCmd);
sqlite3_free(zCmd);
if( x ) fprintf(stderr, "System command returns %d\n", x);
}else
if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
int i;
if( nArg!=1 ){
fprintf(stderr, "Usage: .show\n");
rc = 1;
|
| ︙ | ︙ | |||
3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 |
fprintf(p->out,"%9.9s: ", "nullvalue");
output_c_string(p->out, p->nullvalue);
fprintf(p->out, "\n");
fprintf(p->out,"%9.9s: %s\n","output",
strlen30(p->outfile) ? p->outfile : "stdout");
fprintf(p->out,"%9.9s: ", "separator");
output_c_string(p->out, p->separator);
fprintf(p->out, "\n");
fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
fprintf(p->out,"%9.9s: ","width");
for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
fprintf(p->out,"%d ",p->colWidth[i]);
}
fprintf(p->out,"\n");
| > > | 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 |
fprintf(p->out,"%9.9s: ", "nullvalue");
output_c_string(p->out, p->nullvalue);
fprintf(p->out, "\n");
fprintf(p->out,"%9.9s: %s\n","output",
strlen30(p->outfile) ? p->outfile : "stdout");
fprintf(p->out,"%9.9s: ", "separator");
output_c_string(p->out, p->separator);
fprintf(p->out," ");
output_c_string(p->out, p->newline);
fprintf(p->out, "\n");
fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
fprintf(p->out,"%9.9s: ","width");
for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
fprintf(p->out,"%d ",p->colWidth[i]);
}
fprintf(p->out,"\n");
|
| ︙ | ︙ | |||
3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 | " -interactive force interactive I/O\n" " -line set output mode to 'line'\n" " -list set output mode to 'list'\n" " -mmap N default mmap size set to N\n" #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif " -nullvalue TEXT set text string for NULL values. Default ''\n" " -separator SEP set output field separator. Default: '|'\n" " -stats print memory stats before each finalize\n" " -version show SQLite version\n" " -vfs NAME use NAME as the default VFS\n" #ifdef SQLITE_ENABLE_VFSTRACE " -vfstrace enable tracing of all VFS calls\n" | > | 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 | " -interactive force interactive I/O\n" " -line set output mode to 'line'\n" " -list set output mode to 'list'\n" " -mmap N default mmap size set to N\n" #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif " -newline SEP set newline character(s) for CSV\n" " -nullvalue TEXT set text string for NULL values. Default ''\n" " -separator SEP set output field separator. Default: '|'\n" " -stats print memory stats before each finalize\n" " -version show SQLite version\n" " -vfs NAME use NAME as the default VFS\n" #ifdef SQLITE_ENABLE_VFSTRACE " -vfstrace enable tracing of all VFS calls\n" |
| ︙ | ︙ | |||
3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 |
/*
** Initialize the state information in data
*/
static void main_init(struct callback_data *data) {
memset(data, 0, sizeof(*data));
data->mode = MODE_List;
memcpy(data->separator,"|", 2);
data->showHeader = 0;
sqlite3_config(SQLITE_CONFIG_URI, 1);
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
}
| > | 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 |
/*
** Initialize the state information in data
*/
static void main_init(struct callback_data *data) {
memset(data, 0, sizeof(*data));
data->mode = MODE_List;
memcpy(data->separator,"|", 2);
memcpy(data->newline,"\r\n", 3);
data->showHeader = 0;
sqlite3_config(SQLITE_CONFIG_URI, 1);
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
}
|
| ︙ | ︙ | |||
3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 |
fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);
fprintf(stderr,"Use -help for a list of options.\n");
return 1;
}
if( z[1]=='-' ) z++;
if( strcmp(z,"-separator")==0
|| strcmp(z,"-nullvalue")==0
|| strcmp(z,"-cmd")==0
){
(void)cmdline_option_value(argc, argv, ++i);
}else if( strcmp(z,"-init")==0 ){
zInitFile = cmdline_option_value(argc, argv, ++i);
}else if( strcmp(z,"-batch")==0 ){
/* Need to check for batch mode here to so we can avoid printing
| > | 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 |
fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);
fprintf(stderr,"Use -help for a list of options.\n");
return 1;
}
if( z[1]=='-' ) z++;
if( strcmp(z,"-separator")==0
|| strcmp(z,"-nullvalue")==0
|| strcmp(z,"-newline")==0
|| strcmp(z,"-cmd")==0
){
(void)cmdline_option_value(argc, argv, ++i);
}else if( strcmp(z,"-init")==0 ){
zInitFile = cmdline_option_value(argc, argv, ++i);
}else if( strcmp(z,"-batch")==0 ){
/* Need to check for batch mode here to so we can avoid printing
|
| ︙ | ︙ | |||
3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 |
data.mode = MODE_Column;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.separator,",",2);
}else if( strcmp(z,"-separator")==0 ){
sqlite3_snprintf(sizeof(data.separator), data.separator,
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-nullvalue")==0 ){
sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-header")==0 ){
data.showHeader = 1;
}else if( strcmp(z,"-noheader")==0 ){
data.showHeader = 0;
| > > > | 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 |
data.mode = MODE_Column;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.separator,",",2);
}else if( strcmp(z,"-separator")==0 ){
sqlite3_snprintf(sizeof(data.separator), data.separator,
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-newline")==0 ){
sqlite3_snprintf(sizeof(data.newline), data.newline,
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-nullvalue")==0 ){
sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
"%s",cmdline_option_value(argc,argv,++i));
}else if( strcmp(z,"-header")==0 ){
data.showHeader = 1;
}else if( strcmp(z,"-noheader")==0 ){
data.showHeader = 0;
|
| ︙ | ︙ |
Changes to src/sqlite3.c.
| ︙ | ︙ | |||
220 221 222 223 224 225 226 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.6" #define SQLITE_VERSION_NUMBER 3008006 | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.6" #define SQLITE_VERSION_NUMBER 3008006 #define SQLITE_SOURCE_ID "2014-08-12 16:13:37 6715991296886c2a02b9a285a1e61189ad1f79c0" /* ** 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 |
| ︙ | ︙ | |||
380 381 382 383 384 385 386 | #endif /* ** CAPI3REF: Closing A Database Connection ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. | | | | | 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 | #endif /* ** CAPI3REF: Closing A Database Connection ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. ** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** ** ^If the database connection is associated with unfinalized prepared ** statements or unfinished sqlite3_backup objects then sqlite3_close() ** will leave the database connection open and return [SQLITE_BUSY]. ** ^If sqlite3_close_v2() is called with unfinalized prepared statements ** and/or unfinished sqlite3_backups, then the database connection becomes ** an unusable "zombie" which will automatically be deallocated when the ** last prepared statement is finalized or the last sqlite3_backup is ** finished. The sqlite3_close_v2() interface is intended for use with ** host languages that are garbage collected, and where the order in which ** destructors are called is arbitrary. ** ** Applications should [sqlite3_finalize | finalize] all [prepared statements], ** [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated ** with the [sqlite3] object prior to attempting to close the object. ^If ** sqlite3_close_v2() is called on a [database connection] that still has ** outstanding [prepared statements], [BLOB handles], and/or ** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation ** of resources is deferred until all [prepared statements], [BLOB handles], ** and [sqlite3_backup] objects are also destroyed. ** ** ^If an [sqlite3] object is destroyed while a transaction is open, ** the transaction is automatically rolled back. ** ** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)] |
| ︙ | ︙ | |||
497 498 499 500 501 502 503 | int (*callback)(void*,int,char**,char**), /* Callback function */ void *, /* 1st argument to callback */ char **errmsg /* Error msg written here */ ); /* ** CAPI3REF: Result Codes | < | | < | 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);
/*
** CAPI3REF: Result Codes
** KEYWORDS: {result code definitions}
**
** Many SQLite functions return an integer result code from the set shown
** here in order to indicate success or failure.
**
** New error codes may be added in future versions of SQLite.
**
** See also: [extended result code definitions]
*/
#define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
| ︙ | ︙ | |||
544 545 546 547 548 549 550 | #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ /* end-of-error-codes */ /* ** CAPI3REF: Extended Result Codes | < | | | | | | | < < < < < < | 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 |
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */
/*
** CAPI3REF: Extended Result Codes
** KEYWORDS: {extended result code definitions}
**
** In its default configuration, SQLite API routines return one of 30 integer
** [result codes]. However, experience has shown that many of
** these result codes are too coarse-grained. They do not provide as
** much information about problems as programmers might like. In an effort to
** 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. These [extended result codes] are enabled or disabled
** on a per database connection basis using the
** [sqlite3_extended_result_codes()] API. Or, the extended code for
** the most recent error can be obtained using
** [sqlite3_extended_errcode()].
*/
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))
#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))
|
| ︙ | ︙ | |||
796 797 798 799 800 801 802 | ** integer opcode. The third argument is a generic pointer intended to ** point to a structure that may contain arguments or space in which to ** write return values. Potential uses for xFileControl() might be ** functions to enable blocking locks with timeouts, to change the ** locking strategy (for example to use dot-file locks), to inquire ** about the status of a lock, or to break stale locks. The SQLite ** core reserves all opcodes less than 100 for its own use. | | | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 | ** integer opcode. The third argument is a generic pointer intended to ** point to a structure that may contain arguments or space in which to ** write return values. Potential uses for xFileControl() might be ** functions to enable blocking locks with timeouts, to change the ** locking strategy (for example to use dot-file locks), to inquire ** about the status of a lock, or to break stale locks. The SQLite ** core reserves all opcodes less than 100 for its own use. ** A [file control opcodes | list of opcodes] less than 100 is available. ** Applications that define a custom xFileControl method should use opcodes ** greater than 100 to avoid conflicts. VFS implementations should ** return [SQLITE_NOTFOUND] for file control opcodes that they do not ** recognize. ** ** The xSectorSize() method returns the sector size of the ** device that underlies the file. The sector size is the |
| ︙ | ︙ | |||
869 870 871 872 873 874 875 876 877 878 879 880 881 882 | int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); /* Methods above are valid for version 3 */ /* Additional methods may be added in future releases */ }; /* ** CAPI3REF: Standard File Control Opcodes ** ** These integer constants are opcodes for the xFileControl method ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] ** interface. ** ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of | > | 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 |
int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);
/* Methods above are valid for version 3 */
/* Additional methods may be added in future releases */
};
/*
** CAPI3REF: Standard File Control Opcodes
** KEYWORDS: {file control opcodes} {file control opcode}
**
** These integer constants are opcodes for the xFileControl method
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
** interface.
**
** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
** opcode causes the xFileControl method to write the current state of
|
| ︙ | ︙ | |||
2148 2149 2150 2151 2152 2153 2154 | */ SQLITE_API int sqlite3_complete(const char *sql); SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** | | > | > | > > | | | > | | > < < < < < < < < < < < < < < < > | | > | > > | 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 | */ SQLITE_API int sqlite3_complete(const char *sql); SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** ** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X ** that might be invoked with argument P whenever ** an attempt is made to access a database table associated with ** [database connection] D when another thread ** or process has the table locked. ** The sqlite3_busy_handler() interface is used to implement ** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. ** ** ^If the busy callback is NULL, then [SQLITE_BUSY] ** is returned immediately upon encountering the lock. ^If the busy callback ** is not NULL, then the callback might be invoked with two arguments. ** ** ^The first argument to the busy handler is a copy of the void* pointer which ** is the third argument to sqlite3_busy_handler(). ^The second argument to ** the busy handler callback is the number of times that the busy handler has ** been invoked for the same locking event. ^If the ** busy callback returns 0, then no additional attempts are made to ** access the database and [SQLITE_BUSY] is returned ** to the application. ** ^If the callback returns non-zero, then another attempt ** is made to access the database and the cycle repeats. ** ** The presence of a busy handler does not guarantee that it will be invoked ** when there is lock contention. ^If SQLite determines that invoking the busy ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] ** to the application instead of invoking the ** busy handler. ** Consider a scenario where one process is holding a read lock that ** it is trying to promote to a reserved lock and ** a second process is holding a reserved lock that it is trying ** to promote to an exclusive lock. The first process cannot proceed ** because it is blocked by the second and the second process cannot ** proceed because it is blocked by the first. If both processes ** invoke the busy handlers, neither will make any progress. Therefore, ** SQLite returns [SQLITE_BUSY] for the first process, hoping that this ** will induce the first process to release its read lock and allow ** the second process to proceed. ** ** ^The default busy callback is NULL. ** ** ^(There can only be a single busy handler defined for each ** [database connection]. Setting a new busy handler clears any ** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] ** or evaluating [PRAGMA busy_timeout=N] will change the ** busy handler and thus clear any previously set busy handler. ** ** The busy callback should not take any actions which modify the ** database connection that invoked the busy handler. In other words, ** the busy handler is not reentrant. Any such actions ** result in undefined behavior. ** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); /* ** CAPI3REF: Set A Busy Timeout ** ** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps ** for a specified amount of time when a table is locked. ^The handler ** will sleep multiple times until at least "ms" milliseconds of sleeping ** have accumulated. ^After at least "ms" milliseconds of sleeping, ** the handler returns 0 which causes [sqlite3_step()] to return ** [SQLITE_BUSY]. ** ** ^Calling this routine with an argument less than or equal to zero ** turns off all busy handlers. ** ** ^(There can only be a single busy handler for a particular ** [database connection] any any given moment. If another busy handler ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ ** ** See also: [PRAGMA busy_timeout] */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Convenience Routines For Running Queries ** ** This is a legacy interface that is preserved for backwards compatibility. |
| ︙ | ︙ | |||
2629 2630 2631 2632 2633 2634 2635 | ** ** The [sqlite3_set_authorizer | authorizer callback function] must ** return either [SQLITE_OK] or one of these two constants in order ** to signal SQLite whether or not the action is permitted. See the ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. ** | | | | 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 | ** ** The [sqlite3_set_authorizer | authorizer callback function] must ** return either [SQLITE_OK] or one of these two constants in order ** to signal SQLite whether or not the action is permitted. See the ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. ** ** Note that SQLITE_IGNORE is also used as a [conflict resolution mode] ** returned from the [sqlite3_vtab_on_conflict()] interface. */ #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ /* ** CAPI3REF: Authorizer Action Codes ** |
| ︙ | ︙ | |||
4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 | ** ** ^(If this global variable is made to point to a string which is ** the name of a folder (a.k.a. directory), then all temporary files ** created by SQLite when using a built-in [sqlite3_vfs | VFS] ** will be placed in that directory.)^ ^If this variable ** is a NULL pointer, then SQLite performs a search for an appropriate ** temporary file directory. ** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate ** thread. ** It is intended that this variable be set once ** as part of process initialization and before any SQLite interface ** routines have been called and that this variable remain unchanged ** thereafter. ** ** ^The [temp_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [temp_store_directory pragma] always assumes that any string ** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [temp_store_directory pragma] should be avoided. ** ** <b>Note to Windows Runtime users:</b> The temporary directory must be set ** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various ** features that require the use of temporary files may fail. Here is an ** example of how to do this using C++ with the Windows Runtime: ** ** <blockquote><pre> | > > > > > > > > > > > > | 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 | ** ** ^(If this global variable is made to point to a string which is ** the name of a folder (a.k.a. directory), then all temporary files ** created by SQLite when using a built-in [sqlite3_vfs | VFS] ** will be placed in that directory.)^ ^If this variable ** is a NULL pointer, then SQLite performs a search for an appropriate ** temporary file directory. ** ** Applications are strongly discouraged from using this global variable. ** It is required to set a temporary folder on Windows Runtime (WinRT). ** But for all other platforms, it is highly recommended that applications ** neither read nor write this variable. This global variable is a relic ** that exists for backwards compatibility of legacy applications and should ** be avoided in new projects. ** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate ** thread. ** It is intended that this variable be set once ** as part of process initialization and before any SQLite interface ** routines have been called and that this variable remain unchanged ** thereafter. ** ** ^The [temp_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [temp_store_directory pragma] always assumes that any string ** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [temp_store_directory pragma] should be avoided. ** Except when requested by the [temp_store_directory pragma], SQLite ** does not free the memory that sqlite3_temp_directory points to. If ** the application wants that memory to be freed, it must do ** so itself, taking care to only do so after all [database connection] ** objects have been destroyed. ** ** <b>Note to Windows Runtime users:</b> The temporary directory must be set ** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various ** features that require the use of temporary files may fail. Here is an ** example of how to do this using C++ with the Windows Runtime: ** ** <blockquote><pre> |
| ︙ | ︙ | |||
5969 5970 5971 5972 5973 5974 5975 | ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM | | | > > | 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 | ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_OPEN ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_PMEM ** <li> SQLITE_MUTEX_STATIC_APP1 ** <li> SQLITE_MUTEX_STATIC_APP2 ** </ul>)^ ** ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) ** cause sqlite3_mutex_alloc() to create ** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction |
| ︙ | ︙ | |||
6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 | #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ #define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ /* ** CAPI3REF: Retrieve the mutex for a database connection ** ** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. | > > > | 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 | #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ #define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ #define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ #define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ #define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ /* ** CAPI3REF: Retrieve the mutex for a database connection ** ** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. |
| ︙ | ︙ | |||
6271 6272 6273 6274 6275 6276 6277 | #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_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 | > | | 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 | #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_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_LAST 23 /* ** 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 |
| ︙ | ︙ | |||
7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 | ** ^The callback registered by this function replaces any existing callback ** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback ** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism ** configured by this function. ** ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface ** from SQL. ** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] ** pages. The use of this interface ** is only necessary if the default setting is found to be suboptimal ** for a particular application. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database ** ** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X ** on [database connection] D to be [checkpointed]. ^If X is NULL or an ** empty string, then a checkpoint is run on all databases of ** connection D. ^If the database connection D is not in ** [WAL | write-ahead log mode] then this interface is a harmless no-op. ** ** ^The [wal_checkpoint pragma] can be used to invoke this interface ** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] can be used to cause this interface to be ** run whenever the WAL reaches a certain size threshold. ** ** See also: [sqlite3_wal_checkpoint_v2()] | > > > > > > > | 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 | ** ^The callback registered by this function replaces any existing callback ** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback ** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism ** configured by this function. ** ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface ** from SQL. ** ** ^Checkpoints initiated by this mechanism are ** [sqlite3_wal_checkpoint_v2|PASSIVE]. ** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] ** pages. The use of this interface ** is only necessary if the default setting is found to be suboptimal ** for a particular application. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database ** ** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X ** on [database connection] D to be [checkpointed]. ^If X is NULL or an ** empty string, then a checkpoint is run on all databases of ** connection D. ^If the database connection D is not in ** [WAL | write-ahead log mode] then this interface is a harmless no-op. ** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a ** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint. ** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL ** or RESET checkpoint. ** ** ^The [wal_checkpoint pragma] can be used to invoke this interface ** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] can be used to cause this interface to be ** run whenever the WAL reaches a certain size threshold. ** ** See also: [sqlite3_wal_checkpoint_v2()] |
| ︙ | ︙ | |||
7293 7294 7295 7296 7297 7298 7299 | ** eMode parameter: ** ** <dl> ** <dt>SQLITE_CHECKPOINT_PASSIVE<dd> ** Checkpoint as many frames as possible without waiting for any database ** readers or writers to finish. Sync the db file if all frames in the log ** are checkpointed. This mode is the same as calling | | > | > | > | 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 | ** eMode parameter: ** ** <dl> ** <dt>SQLITE_CHECKPOINT_PASSIVE<dd> ** Checkpoint as many frames as possible without waiting for any database ** readers or writers to finish. Sync the db file if all frames in the log ** are checkpointed. This mode is the same as calling ** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback] ** is never invoked. ** ** <dt>SQLITE_CHECKPOINT_FULL<dd> ** This mode blocks (it invokes the ** [sqlite3_busy_handler|busy-handler callback]) until there is no ** database writer and all readers are reading from the most recent database ** snapshot. It then checkpoints all frames in the log file and syncs the ** database file. This call blocks database writers while it is running, ** but not database readers. ** ** <dt>SQLITE_CHECKPOINT_RESTART<dd> ** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after ** checkpointing the log file it blocks (calls the ** [sqlite3_busy_handler|busy-handler callback]) ** until all readers are reading from the database file only. This ensures ** that the next client to write to the database file restarts the log file ** from the beginning. This call blocks database writers while it is running, ** but not database readers. ** </dl> ** ** If pnLog is not NULL, then *pnLog is set to the total number of frames in |
| ︙ | ︙ | |||
7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 | ** of the SQL statement that triggered the call to the [xUpdate] method of the ** [virtual table]. */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Conflict resolution modes ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to ** inform a [virtual table] implementation what the [ON CONFLICT] mode ** is for the SQL statement being evaluated. ** ** Note that the [SQLITE_IGNORE] constant is also used as a potential ** return value from the [sqlite3_set_authorizer()] callback and that | > | 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 |
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode}
**
** These constants are returned by [sqlite3_vtab_on_conflict()] to
** inform a [virtual table] implementation what the [ON CONFLICT] mode
** is for the SQL statement being evaluated.
**
** Note that the [SQLITE_IGNORE] constant is also used as a potential
** return value from the [sqlite3_set_authorizer()] callback and that
|
| ︙ | ︙ | |||
9283 9284 9285 9286 9287 9288 9289 | #define OP_IfNot 45 #define OP_Column 46 /* synopsis: r[P3]=PX */ #define OP_Affinity 47 /* synopsis: affinity(r[P1@P2]) */ #define OP_MakeRecord 48 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ #define OP_Count 49 /* synopsis: r[P2]=count() */ #define OP_ReadCookie 50 #define OP_SetCookie 51 | | | > | | | | | | | | | | | | | | | | < > | | < | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < > | | | | | | | | < > | | | | | | | | | | | 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 | #define OP_IfNot 45 #define OP_Column 46 /* synopsis: r[P3]=PX */ #define OP_Affinity 47 /* synopsis: affinity(r[P1@P2]) */ #define OP_MakeRecord 48 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ #define OP_Count 49 /* synopsis: r[P2]=count() */ #define OP_ReadCookie 50 #define OP_SetCookie 51 #define OP_ReopenIdx 52 /* synopsis: root=P2 iDb=P3 */ #define OP_OpenRead 53 /* synopsis: root=P2 iDb=P3 */ #define OP_OpenWrite 54 /* synopsis: root=P2 iDb=P3 */ #define OP_OpenAutoindex 55 /* synopsis: nColumn=P2 */ #define OP_OpenEphemeral 56 /* synopsis: nColumn=P2 */ #define OP_SorterOpen 57 #define OP_OpenPseudo 58 /* synopsis: P3 columns in r[P2] */ #define OP_Close 59 #define OP_SeekLT 60 /* synopsis: key=r[P3@P4] */ #define OP_SeekLE 61 /* synopsis: key=r[P3@P4] */ #define OP_SeekGE 62 /* synopsis: key=r[P3@P4] */ #define OP_SeekGT 63 /* synopsis: key=r[P3@P4] */ #define OP_Seek 64 /* synopsis: intkey=r[P2] */ #define OP_NoConflict 65 /* synopsis: key=r[P3@P4] */ #define OP_NotFound 66 /* synopsis: key=r[P3@P4] */ #define OP_Found 67 /* synopsis: key=r[P3@P4] */ #define OP_NotExists 68 /* synopsis: intkey=r[P3] */ #define OP_Sequence 69 /* synopsis: r[P2]=cursor[P1].ctr++ */ #define OP_NewRowid 70 /* synopsis: r[P2]=rowid */ #define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ #define OP_Insert 73 /* synopsis: intkey=r[P3] data=r[P2] */ #define OP_InsertInt 74 /* synopsis: intkey=P3 data=r[P2] */ #define OP_Delete 75 #define OP_IsNull 76 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 77 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 78 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */ #define OP_Eq 79 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */ #define OP_Gt 80 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */ #define OP_Le 81 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */ #define OP_Lt 82 /* same as TK_LT, synopsis: if r[P1]<r[P3] goto P2 */ #define OP_Ge 83 /* same as TK_GE, synopsis: if r[P1]>=r[P3] goto P2 */ #define OP_ResetCount 84 #define OP_BitAnd 85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */ #define OP_ShiftRight 88 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */ #define OP_Add 89 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ #define OP_Subtract 90 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ #define OP_Multiply 91 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ #define OP_Divide 92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ #define OP_Remainder 93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ #define OP_Concat 94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ #define OP_SorterCompare 95 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ #define OP_BitNot 96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ #define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */ #define OP_SorterData 98 /* synopsis: r[P2]=data */ #define OP_RowKey 99 /* synopsis: r[P2]=key */ #define OP_RowData 100 /* synopsis: r[P2]=data */ #define OP_Rowid 101 /* synopsis: r[P2]=rowid */ #define OP_NullRow 102 #define OP_Last 103 #define OP_SorterSort 104 #define OP_Sort 105 #define OP_Rewind 106 #define OP_SorterInsert 107 #define OP_IdxInsert 108 /* synopsis: key=r[P2] */ #define OP_IdxDelete 109 /* synopsis: key=r[P2@P3] */ #define OP_IdxRowid 110 /* synopsis: r[P2]=rowid */ #define OP_IdxLE 111 /* synopsis: key=r[P3@P4] */ #define OP_IdxGT 112 /* synopsis: key=r[P3@P4] */ #define OP_IdxLT 113 /* synopsis: key=r[P3@P4] */ #define OP_IdxGE 114 /* synopsis: key=r[P3@P4] */ #define OP_Destroy 115 #define OP_Clear 116 #define OP_ResetSorter 117 #define OP_CreateIndex 118 /* synopsis: r[P2]=root iDb=P1 */ #define OP_CreateTable 119 /* synopsis: r[P2]=root iDb=P1 */ #define OP_ParseSchema 120 #define OP_LoadAnalysis 121 #define OP_DropTable 122 #define OP_DropIndex 123 #define OP_DropTrigger 124 #define OP_IntegrityCk 125 #define OP_RowSetAdd 126 /* synopsis: rowset(P1)=r[P2] */ #define OP_RowSetRead 127 /* synopsis: r[P3]=rowset(P1) */ #define OP_RowSetTest 128 /* synopsis: if r[P3] in rowset(P1) goto P2 */ #define OP_Program 129 #define OP_Param 130 #define OP_FkCounter 131 /* synopsis: fkctr[P1]+=P2 */ #define OP_FkIfZero 132 /* synopsis: if fkctr[P1]==0 goto P2 */ #define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ #define OP_MemMax 134 /* synopsis: r[P1]=max(r[P1],r[P2]) */ #define OP_IfPos 135 /* synopsis: if r[P1]>0 goto P2 */ #define OP_IfNeg 136 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */ #define OP_IfZero 137 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ #define OP_AggFinal 138 /* synopsis: accum=r[P1] N=P2 */ #define OP_IncrVacuum 139 #define OP_Expire 140 #define OP_TableLock 141 /* synopsis: iDb=P1 root=P2 write=P3 */ #define OP_VBegin 142 #define OP_ToText 143 /* same as TK_TO_TEXT */ #define OP_ToBlob 144 /* same as TK_TO_BLOB */ #define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */ #define OP_ToInt 146 /* same as TK_TO_INT */ #define OP_ToReal 147 /* same as TK_TO_REAL */ #define OP_VCreate 148 #define OP_VDestroy 149 #define OP_VOpen 150 #define OP_VColumn 151 /* synopsis: r[P3]=vcolumn(P2) */ #define OP_VNext 152 #define OP_VRename 153 #define OP_Pagecount 154 #define OP_MaxPgcnt 155 #define OP_Init 156 /* synopsis: Start at P2 */ #define OP_Noop 157 #define OP_Explain 158 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c ** are encoded into bitvectors as follows: */ #define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */ |
| ︙ | ︙ | |||
9410 9411 9412 9413 9414 9415 9416 | /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,\ /* 8 */ 0x01, 0x01, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\ /* 16 */ 0x01, 0x01, 0x04, 0x24, 0x01, 0x04, 0x05, 0x10,\ /* 24 */ 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02,\ /* 32 */ 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x05, 0x04,\ /* 40 */ 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00,\ /* 48 */ 0x00, 0x02, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00,\ | | | | | | | | | | | | 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 | /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,\ /* 8 */ 0x01, 0x01, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\ /* 16 */ 0x01, 0x01, 0x04, 0x24, 0x01, 0x04, 0x05, 0x10,\ /* 24 */ 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02,\ /* 32 */ 0x00, 0x00, 0x20, 0x00, 0x00, 0x04, 0x05, 0x04,\ /* 40 */ 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00,\ /* 48 */ 0x00, 0x02, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00,\ /* 56 */ 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\ /* 64 */ 0x08, 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x4c,\ /* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\ /* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\ /* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\ /* 96 */ 0x24, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,\ /* 104 */ 0x01, 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01,\ /* 112 */ 0x01, 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02,\ /* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45,\ /* 128 */ 0x15, 0x01, 0x02, 0x00, 0x01, 0x02, 0x08, 0x05,\ /* 136 */ 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04,\ /* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,\ /* 152 */ 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,} /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. |
| ︙ | ︙ | |||
10329 10330 10331 10332 10333 10334 10335 | Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ Hash fkeyHash; /* All foreign keys by referenced table name */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ | | | | | | | 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 | Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ Hash fkeyHash; /* All foreign keys by referenced table name */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ u16 schemaFlags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ }; /* ** These macros can be used to test, set, or clear bits in the ** Db.pSchema->flags field. */ #define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P)) #define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))!=0) #define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags|=(P) #define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags&=~(P) /* ** Allowed values for the DB.pSchema->flags field. ** ** The DB_SchemaLoaded flag is set after the database schema has been ** read into internal hash tables. ** |
| ︙ | ︙ | |||
10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 | #endif LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ int tnum; /* Root BTree node for this table (see note above) */ i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */ i16 nCol; /* Number of columns in this table */ u16 nRef; /* Number of pointers to this Table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE int nModuleArg; /* Number of arguments to the module */ | > > > | 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 | #endif LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ int tnum; /* Root BTree node for this table (see note above) */ i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */ i16 nCol; /* Number of columns in this table */ u16 nRef; /* Number of pointers to this Table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT LogEst costMult; /* Cost multiplier for using this table */ #endif u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE int nModuleArg; /* Number of arguments to the module */ |
| ︙ | ︙ | |||
11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 |
#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */
#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */
#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */
/* Return true if index X is a PRIMARY KEY index */
#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY)
/*
** Each sample stored in the sqlite_stat3 table is represented in memory
** using a structure of this type. See documentation at the top of the
** analyze.c source file for additional information.
*/
struct IndexSample {
void *p; /* Pointer to sampled record */
| > > > | 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204 11205 11206 |
#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */
#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */
#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */
/* Return true if index X is a PRIMARY KEY index */
#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY)
/* Return true if index X is a UNIQUE index */
#define IsUniqueIndex(X) ((X)->onError!=OE_None)
/*
** Each sample stored in the sqlite_stat3 table is represented in memory
** using a structure of this type. See documentation at the top of the
** analyze.c source file for additional information.
*/
struct IndexSample {
void *p; /* Pointer to sampled record */
|
| ︙ | ︙ | |||
11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 | #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ #define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ #define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ /* Allowed return values from sqlite3WhereIsDistinct() */ #define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ #define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ #define WHERE_DISTINCT_ORDERED 2 /* All duplicates are adjacent */ #define WHERE_DISTINCT_UNORDERED 3 /* Duplicates are scattered */ | > | 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 | #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ #define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ #define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ #define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */ /* Allowed return values from sqlite3WhereIsDistinct() */ #define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ #define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ #define WHERE_DISTINCT_ORDERED 2 /* All duplicates are adjacent */ #define WHERE_DISTINCT_UNORDERED 3 /* Duplicates are scattered */ |
| ︙ | ︙ | |||
11845 11846 11847 11848 11849 11850 11851 | u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */ }; /* ** The yDbMask datatype for the bitmask of all attached databases. */ #if SQLITE_MAX_ATTACHED>30 | | > > > > > > > > > > | 11869 11870 11871 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 11895 | u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */ }; /* ** The yDbMask datatype for the bitmask of all attached databases. */ #if SQLITE_MAX_ATTACHED>30 typedef unsigned char yDbMask[(SQLITE_MAX_ATTACHED+9)/8]; # define DbMaskTest(M,I) (((M)[(I)/8]&(1<<((I)&7)))!=0) # define DbMaskZero(M) memset((M),0,sizeof(M)) # define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7)) # define DbMaskAllZero(M) sqlite3DbMaskAllZero(M) # define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0) #else typedef unsigned int yDbMask; # define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) # define DbMaskZero(M) (M)=0 # define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I)) # define DbMaskAllZero(M) (M)==0 # define DbMaskNonZero(M) (M)!=0 #endif /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to ** carry around information that is global to the entire parse. ** |
| ︙ | ︙ | |||
12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531 12532 12533 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*); #else # define sqlite3ViewGetColumnNames(A,B) 0 #endif SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); #ifndef SQLITE_OMIT_AUTOINCREMENT SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); #else | > > > | 12554 12555 12556 12557 12558 12559 12560 12561 12562 12563 12564 12565 12566 12567 12568 12569 12570 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*); #else # define sqlite3ViewGetColumnNames(A,B) 0 #endif #if SQLITE_MAX_ATTACHED>30 SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask); #endif SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); #ifndef SQLITE_OMIT_AUTOINCREMENT SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); #else |
| ︙ | ︙ | |||
12770 12771 12772 12773 12774 12775 12776 12777 12778 12779 12780 12781 12782 12783 | SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *); SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int); SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); SQLITE_PRIVATE u8 sqlite3HexToInt(int h); SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); #if defined(SQLITE_TEST) SQLITE_PRIVATE const char *sqlite3ErrName(int); | > | 12807 12808 12809 12810 12811 12812 12813 12814 12815 12816 12817 12818 12819 12820 12821 | SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *); SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int); SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*); SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); SQLITE_PRIVATE u8 sqlite3HexToInt(int h); SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); #if defined(SQLITE_TEST) SQLITE_PRIVATE const char *sqlite3ErrName(int); |
| ︙ | ︙ | |||
12799 12800 12801 12802 12803 12804 12805 | SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64); SQLITE_PRIVATE int sqlite3AbsInt32(int); #ifdef SQLITE_ENABLE_8_3_NAMES SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*); #else # define sqlite3FileSuffix3(X,Y) #endif | | | 12837 12838 12839 12840 12841 12842 12843 12844 12845 12846 12847 12848 12849 12850 12851 |
SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
SQLITE_PRIVATE int sqlite3AbsInt32(int);
#ifdef SQLITE_ENABLE_8_3_NAMES
SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*);
#else
# define sqlite3FileSuffix3(X,Y)
#endif
SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8);
SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*);
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
|
| ︙ | ︙ | |||
13023 13024 13025 13026 13027 13028 13029 | SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void); SQLITE_PRIVATE void sqlite3EndBenignMalloc(void); #else #define sqlite3BeginBenignMalloc() #define sqlite3EndBenignMalloc() #endif | > > > | | | | > > > > > > > | | 13061 13062 13063 13064 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 | SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void); SQLITE_PRIVATE void sqlite3EndBenignMalloc(void); #else #define sqlite3BeginBenignMalloc() #define sqlite3EndBenignMalloc() #endif /* ** Allowed return values from sqlite3FindInIndex() */ #define IN_INDEX_ROWID 1 /* Search the rowid of the table */ #define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */ #define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */ #define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */ #define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ /* ** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). */ #define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ #define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ #define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*); #ifdef SQLITE_ENABLE_ATOMIC_WRITE SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *); SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *); SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p); #else |
| ︙ | ︙ | |||
13874 13875 13876 13877 13878 13879 13880 13881 13882 13883 13884 13885 13886 13887 13888 13889 13890 13891 13892 13893 13894 13895 | BtCursor *pCursor; /* The cursor structure of the backend */ Btree *pBt; /* Separate file holding temporary table */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ int seekResult; /* Result of previous sqlite3BtreeMoveto() */ int pseudoTableReg; /* Register holding pseudotable content. */ i16 nField; /* Number of fields in the header */ u16 nHdrParsed; /* Number of header fields parsed so far */ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ u8 rowidIsValid; /* True if lastRowid is valid */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Rowid being deleted by OP_Delete */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ /* Cached information about the header for the data record that the | > > > > | 13922 13923 13924 13925 13926 13927 13928 13929 13930 13931 13932 13933 13934 13935 13936 13937 13938 13939 13940 13941 13942 13943 13944 13945 13946 13947 | BtCursor *pCursor; /* The cursor structure of the backend */ Btree *pBt; /* Separate file holding temporary table */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ int seekResult; /* Result of previous sqlite3BtreeMoveto() */ int pseudoTableReg; /* Register holding pseudotable content. */ i16 nField; /* Number of fields in the header */ u16 nHdrParsed; /* Number of header fields parsed so far */ #ifdef SQLITE_DEBUG u8 seekOp; /* Most recent seek operation on this cursor */ #endif i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ u8 rowidIsValid; /* True if lastRowid is valid */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ Pgno pgnoRoot; /* Root page of the open btree cursor */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Rowid being deleted by OP_Delete */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ /* Cached information about the header for the data record that the |
| ︙ | ︙ | |||
18394 18395 18396 18397 18398 18399 18400 |
}
/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
| | | 18446 18447 18448 18449 18450 18451 18452 18453 18454 18455 18456 18457 18458 18459 18460 |
}
/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
#endif
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
if( !sqlite3GlobalConfig.bCoreMutex ){
return 0;
|
| ︙ | ︙ | |||
18575 18576 18577 18578 18579 18580 18581 |
/*
** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
| | | 18627 18628 18629 18630 18631 18632 18633 18634 18635 18636 18637 18638 18639 18640 18641 |
/*
** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1];
sqlite3_debug_mutex *pNew = 0;
switch( id ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
pNew = sqlite3Malloc(sizeof(*pNew));
if( pNew ){
pNew->id = id;
|
| ︙ | ︙ | |||
18772 18773 18774 18775 18776 18777 18778 | ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM | | > > > | 18824 18825 18826 18827 18828 18829 18830 18831 18832 18833 18834 18835 18836 18837 18838 18839 18840 18841 18842 18843 18844 | ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_OPEN ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_PMEM ** <li> SQLITE_MUTEX_STATIC_APP1 ** <li> SQLITE_MUTEX_STATIC_APP2 ** <li> SQLITE_MUTEX_STATIC_APP3 ** </ul> ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does |
| ︙ | ︙ | |||
18804 18805 18806 18807 18808 18809 18810 18811 18812 18813 18814 18815 18816 18817 |
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
static sqlite3_mutex *pthreadMutexAlloc(int iType){
static sqlite3_mutex staticMutexes[] = {
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
};
| > > > | 18859 18860 18861 18862 18863 18864 18865 18866 18867 18868 18869 18870 18871 18872 18873 18874 18875 |
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
static sqlite3_mutex *pthreadMutexAlloc(int iType){
static sqlite3_mutex staticMutexes[] = {
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
};
|
| ︙ | ︙ | |||
19039 19040 19041 19042 19043 19044 19045 | ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 19097 19098 19099 19100 19101 19102 19103 19104 19105 19106 19107 19108 19109 19110 19111 19112 19113 19114 19115 19116 19117 19118 19119 19120 19121 19122 19123 19124 19125 19126 19127 19128 19129 19130 19131 19132 19133 19134 19135 19136 19137 19138 19139 19140 19141 19142 19143 19144 19145 19146 19147 19148 19149 19150 19151 19152 19153 19154 19155 19156 19157 19158 19159 19160 19161 19162 19163 19164 19165 19166 19167 19168 19169 19170 19171 19172 19173 19174 19175 19176 19177 19178 19179 19180 19181 19182 19183 19184 19185 19186 19187 19188 19189 19190 19191 19192 19193 19194 19195 19196 19197 19198 19199 19200 19201 19202 19203 19204 19205 19206 19207 19208 19209 19210 19211 19212 19213 19214 19215 19216 19217 19218 19219 19220 19221 19222 19223 19224 19225 19226 19227 19228 19229 19230 19231 19232 19233 19234 19235 19236 19237 19238 19239 19240 19241 19242 19243 19244 19245 19246 19247 19248 19249 19250 19251 19252 19253 19254 19255 19256 19257 19258 19259 19260 19261 19262 19263 19264 19265 19266 19267 19268 19269 19270 19271 19272 19273 19274 19275 19276 19277 19278 19279 19280 19281 19282 19283 19284 19285 19286 19287 19288 19289 19290 19291 19292 19293 19294 19295 19296 19297 19298 19299 19300 19301 19302 19303 19304 19305 19306 19307 19308 19309 19310 19311 19312 19313 19314 19315 19316 19317 19318 19319 19320 19321 19322 19323 19324 19325 19326 19327 |
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the C functions that implement mutexes for Win32.
*/
#if SQLITE_OS_WIN
/*
** Include code that is common to all os_*.c files
*/
/************** Include os_common.h in the middle of mutex_w32.c *************/
/************** Begin file os_common.h ***************************************/
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains macros and a little bit of code that is common to
** all of the platform-specific files (os_*.c) and is #included into those
** files.
**
** This file should be #included by the os_*.c files only. It is not a
** general purpose header file.
*/
#ifndef _OS_COMMON_H_
#define _OS_COMMON_H_
/*
** At least two bugs have slipped in because we changed the MEMORY_DEBUG
** macro to SQLITE_DEBUG and some older makefiles have not yet made the
** switch. The following code should catch this problem at compile-time.
*/
#ifdef MEMORY_DEBUG
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
# ifndef SQLITE_DEBUG_OS_TRACE
# define SQLITE_DEBUG_OS_TRACE 0
# endif
int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;
# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
# define OSTRACE(X)
#endif
/*
** Macros for performance tracing. Normally turned off. Only works
** on i486 hardware.
*/
#ifdef SQLITE_PERFORMANCE_TRACE
/*
** hwtime.h contains inline assembler code for implementing
** high-performance timing routines.
*/
/************** Include hwtime.h in the middle of os_common.h ****************/
/************** Begin file hwtime.h ******************************************/
/*
** 2008 May 27
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains inline asm code for retrieving "high-performance"
** counters for x86 class CPUs.
*/
#ifndef _HWTIME_H_
#define _HWTIME_H_
/*
** The following routine only works on pentium-class (or newer) processors.
** It uses the RDTSC opcode to read the cycle count value out of the
** processor and returns that value. This can be used for high-res
** profiling.
*/
#if (defined(__GNUC__) || defined(_MSC_VER)) && \
(defined(i386) || defined(__i386__) || defined(_M_IX86))
#if defined(__GNUC__)
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned int lo, hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (sqlite_uint64)hi << 32 | lo;
}
#elif defined(_MSC_VER)
__declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
__asm {
rdtsc
ret ; return value at EDX:EAX
}
}
#endif
#elif (defined(__GNUC__) && defined(__x86_64__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long val;
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
#elif (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long long retval;
unsigned long junk;
__asm__ __volatile__ ("\n\
1: mftbu %1\n\
mftb %L0\n\
mftbu %0\n\
cmpw %0,%1\n\
bne 1b"
: "=r" (retval), "=r" (junk));
return retval;
}
#else
#error Need implementation of sqlite3Hwtime() for your platform.
/*
** To compile without implementing sqlite3Hwtime() for your platform,
** you can remove the above #error and use the following
** stub function. You will lose timing support for many
** of the debugging and testing utilities, but it should at
** least compile and run.
*/
SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
#endif
#endif /* !defined(_HWTIME_H_) */
/************** End of hwtime.h **********************************************/
/************** Continuing where we left off in os_common.h ******************/
static sqlite_uint64 g_start;
static sqlite_uint64 g_elapsed;
#define TIMER_START g_start=sqlite3Hwtime()
#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
#define TIMER_ELAPSED g_elapsed
#else
#define TIMER_START
#define TIMER_END
#define TIMER_ELAPSED ((sqlite_uint64)0)
#endif
/*
** If we compile with the SQLITE_TEST macro set, then the following block
** of code will give us the ability to simulate a disk I/O error. This
** is used for testing the I/O recovery logic.
*/
#ifdef SQLITE_TEST
SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
SQLITE_API int sqlite3_diskfull_pending = 0;
SQLITE_API int sqlite3_diskfull = 0;
#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
#define SimulateIOError(CODE) \
if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
|| sqlite3_io_error_pending-- == 1 ) \
{ local_ioerr(); CODE; }
static void local_ioerr(){
IOTRACE(("IOERR\n"));
sqlite3_io_error_hit++;
if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
}
#define SimulateDiskfullError(CODE) \
if( sqlite3_diskfull_pending ){ \
if( sqlite3_diskfull_pending == 1 ){ \
local_ioerr(); \
sqlite3_diskfull = 1; \
sqlite3_io_error_hit = 1; \
CODE; \
}else{ \
sqlite3_diskfull_pending--; \
} \
}
#else
#define SimulateIOErrorBenign(X)
#define SimulateIOError(A)
#define SimulateDiskfullError(A)
#endif
/*
** When testing, keep a count of the number of open files.
*/
#ifdef SQLITE_TEST
SQLITE_API int sqlite3_open_file_count = 0;
#define OpenCounter(X) sqlite3_open_file_count+=(X)
#else
#define OpenCounter(X)
#endif
#endif /* !defined(_OS_COMMON_H_) */
/************** End of os_common.h *******************************************/
/************** Continuing where we left off in mutex_w32.c ******************/
/*
** Include the header file for the Windows VFS.
*/
/************** Include os_win.h in the middle of mutex_w32.c ****************/
/************** Begin file os_win.h ******************************************/
/*
** 2013 November 25
|
| ︙ | ︙ | |||
19122 19123 19124 19125 19126 19127 19128 | /************** End of os_win.h **********************************************/ /************** Continuing where we left off in mutex_w32.c ******************/ #endif /* ** The code in this file is only used if we are compiling multithreaded | | | < < < < < < < < < < < < < < > > | < < < < < < > | | | > < < < < < < < < < < | > > | < | > > > > > > | | | < | > | > | | | | | | > > > | 19393 19394 19395 19396 19397 19398 19399 19400 19401 19402 19403 19404 19405 19406 19407 19408 19409 19410 19411 19412 19413 19414 19415 19416 19417 19418 19419 19420 19421 19422 19423 19424 19425 19426 19427 19428 19429 19430 19431 19432 19433 19434 19435 19436 19437 19438 19439 19440 19441 19442 19443 19444 19445 19446 19447 19448 19449 19450 19451 19452 19453 19454 19455 19456 19457 19458 19459 19460 19461 19462 19463 19464 19465 19466 19467 19468 19469 19470 19471 19472 19473 19474 19475 19476 19477 19478 19479 19480 19481 19482 19483 19484 19485 19486 19487 19488 19489 19490 19491 19492 19493 19494 19495 19496 19497 19498 19499 19500 19501 19502 19503 19504 19505 19506 19507 19508 19509 19510 19511 19512 19513 19514 19515 19516 19517 19518 19519 19520 19521 19522 19523 19524 19525 19526 19527 19528 19529 19530 19531 19532 19533 19534 19535 19536 19537 19538 19539 |
/************** End of os_win.h **********************************************/
/************** Continuing where we left off in mutex_w32.c ******************/
#endif
/*
** The code in this file is only used if we are compiling multithreaded
** on a Win32 system.
*/
#ifdef SQLITE_MUTEX_W32
/*
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
#ifdef SQLITE_DEBUG
volatile int nRef; /* Number of enterances */
volatile DWORD owner; /* Thread holding this mutex */
volatile int trace; /* True to trace changes */
#endif
};
/*
** These are the initializer values used when declaring a "static" mutex
** on Win32. It should be noted that all mutexes require initialization
** on the Win32 platform.
*/
#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
#ifdef SQLITE_DEBUG
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \
0L, (DWORD)0, 0 }
#else
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
#endif
#ifdef SQLITE_DEBUG
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use only inside assert() statements.
*/
static int winMutexHeld(sqlite3_mutex *p){
return p->nRef!=0 && p->owner==GetCurrentThreadId();
}
static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
return p->nRef==0 || p->owner!=tid;
}
static int winMutexNotheld(sqlite3_mutex *p){
DWORD tid = GetCurrentThreadId();
return winMutexNotheld2(p, tid);
}
#endif
/*
** Initialize and deinitialize the mutex subsystem.
*/
static sqlite3_mutex winMutex_staticMutexes[] = {
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
};
static int winMutex_isInit = 0;
static int winMutex_isNt = -1; /* <0 means "need to query" */
/* As the winMutexInit() and winMutexEnd() functions are called as part
** of the sqlite3_initialize() and sqlite3_shutdown() processing, the
** "interlocked" magic used here is probably not strictly necessary.
*/
static LONG volatile winMutex_lock = 0;
SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */
SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
static int winMutexInit(void){
/* The first to increment to 1 does actual initialization */
if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
int i;
for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
#if SQLITE_OS_WINRT
InitializeCriticalSectionEx(&winMutex_staticMutexes[i].mutex, 0, 0);
#else
InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);
#endif
}
winMutex_isInit = 1;
}else{
/* Another thread is (in the process of) initializing the static
** mutexes */
while( !winMutex_isInit ){
sqlite3_win32_sleep(1);
}
}
return SQLITE_OK;
}
static int winMutexEnd(void){
/* The first to decrement to 0 does actual shutdown
** (which should be the last to shutdown.) */
if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){
if( winMutex_isInit==1 ){
int i;
for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
DeleteCriticalSection(&winMutex_staticMutexes[i].mutex);
}
winMutex_isInit = 0;
}
}
return SQLITE_OK;
}
/*
** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL
** that means that a mutex could not be allocated. SQLite
** will unwind its stack and return an error. The argument
** to sqlite3_mutex_alloc() is one of these integer constants:
**
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU
** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** <li> SQLITE_MUTEX_STATIC_APP3
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
** The mutex implementation does not need to make a distinction
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
|
| ︙ | ︙ | |||
19292 19293 19294 19295 19296 19297 19298 | ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or ** SQLITE_MUTEX_RECURSIVE. ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() | | | > > > < > > > > > > > | | > > > > > > | > | > | | > | > > > | > > > | > > | > | | > > > > > | | 19548 19549 19550 19551 19552 19553 19554 19555 19556 19557 19558 19559 19560 19561 19562 19563 19564 19565 19566 19567 19568 19569 19570 19571 19572 19573 19574 19575 19576 19577 19578 19579 19580 19581 19582 19583 19584 19585 19586 19587 19588 19589 19590 19591 19592 19593 19594 19595 19596 19597 19598 19599 19600 19601 19602 19603 19604 19605 19606 19607 19608 19609 19610 19611 19612 19613 19614 19615 19616 19617 19618 19619 19620 19621 19622 19623 19624 19625 19626 19627 19628 19629 19630 19631 19632 19633 19634 19635 19636 19637 19638 19639 19640 19641 19642 19643 19644 19645 19646 19647 19648 19649 19650 19651 19652 19653 19654 19655 19656 19657 19658 19659 19660 19661 19662 19663 19664 19665 19666 19667 19668 19669 19670 19671 19672 19673 19674 19675 19676 19677 19678 19679 19680 19681 19682 19683 19684 19685 19686 19687 19688 19689 19690 19691 19692 19693 19694 19695 19696 19697 19698 19699 19700 19701 19702 19703 19704 19705 19706 19707 19708 19709 19710 19711 19712 19713 19714 19715 19716 19717 19718 19719 19720 19721 19722 19723 |
** may add additional static mutexes. Static mutexes are for internal
** use by SQLite only. Applications that use SQLite mutexes should
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
** SQLITE_MUTEX_RECURSIVE.
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
static sqlite3_mutex *winMutexAlloc(int iType){
sqlite3_mutex *p;
switch( iType ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
#ifdef SQLITE_DEBUG
p->id = iType;
#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC
p->trace = 1;
#endif
#endif
#if SQLITE_OS_WINRT
InitializeCriticalSectionEx(&p->mutex, 0, 0);
#else
InitializeCriticalSection(&p->mutex);
#endif
}
break;
}
default: {
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(winMutex_staticMutexes) );
assert( winMutex_isInit==1 );
p = &winMutex_staticMutexes[iType-2];
#ifdef SQLITE_DEBUG
p->id = iType;
#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
p->trace = 1;
#endif
#endif
break;
}
}
return p;
}
/*
** This routine deallocates a previously
** allocated mutex. SQLite is careful to deallocate every
** mutex that it allocates.
*/
static void winMutexFree(sqlite3_mutex *p){
assert( p );
#ifdef SQLITE_DEBUG
assert( p->nRef==0 && p->owner==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
#endif
assert( winMutex_isInit==1 );
DeleteCriticalSection(&p->mutex);
sqlite3_free(p);
}
/*
** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
** to enter a mutex. If another thread is already within the mutex,
** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
** be entered multiple times by the same thread. In such cases the,
** mutex must be exited an equal number of times before another thread
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
static void winMutexEnter(sqlite3_mutex *p){
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
DWORD tid = GetCurrentThreadId();
#endif
#ifdef SQLITE_DEBUG
assert( p );
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
#else
assert( p );
#endif
assert( winMutex_isInit==1 );
EnterCriticalSection(&p->mutex);
#ifdef SQLITE_DEBUG
assert( p->nRef>0 || p->owner==0 );
p->owner = tid;
p->nRef++;
if( p->trace ){
OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
tid, p, p->trace, p->nRef));
}
#endif
}
static int winMutexTry(sqlite3_mutex *p){
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
DWORD tid = GetCurrentThreadId();
#endif
int rc = SQLITE_BUSY;
assert( p );
assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
/*
** The sqlite3_mutex_try() routine is very rarely used, and when it
** is used it is merely an optimization. So it is OK for it to always
** fail.
**
** The TryEnterCriticalSection() interface is only available on WinNT.
** And some windows compilers complain if you try to use it without
** first doing some #defines that prevent SQLite from building on Win98.
** For that reason, we will omit this optimization for now. See
** ticket #2685.
*/
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400
assert( winMutex_isInit==1 );
assert( winMutex_isNt>=-1 && winMutex_isNt<=1 );
if( winMutex_isNt<0 ){
winMutex_isNt = sqlite3_win32_is_nt();
}
assert( winMutex_isNt==0 || winMutex_isNt==1 );
if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){
#ifdef SQLITE_DEBUG
p->owner = tid;
p->nRef++;
#endif
rc = SQLITE_OK;
}
#else
UNUSED_PARAMETER(p);
#endif
#ifdef SQLITE_DEBUG
if( p->trace ){
OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));
}
#endif
return rc;
}
/*
** The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
static void winMutexLeave(sqlite3_mutex *p){
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
DWORD tid = GetCurrentThreadId();
#endif
assert( p );
#ifdef SQLITE_DEBUG
assert( p->nRef>0 );
assert( p->owner==tid );
p->nRef--;
if( p->nRef==0 ) p->owner = 0;
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
#endif
assert( winMutex_isInit==1 );
LeaveCriticalSection(&p->mutex);
#ifdef SQLITE_DEBUG
if( p->trace ){
OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
tid, p, p->trace, p->nRef));
}
#endif
}
SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
static const sqlite3_mutex_methods sMutex = {
winMutexInit,
|
| ︙ | ︙ | |||
19443 19444 19445 19446 19447 19448 19449 |
winMutexHeld,
winMutexNotheld
#else
0,
0
#endif
};
| < > | 19731 19732 19733 19734 19735 19736 19737 19738 19739 19740 19741 19742 19743 19744 19745 19746 19747 |
winMutexHeld,
winMutexNotheld
#else
0,
0
#endif
};
return &sMutex;
}
#endif /* SQLITE_MUTEX_W32 */
/************** End of mutex_w32.c *******************************************/
/************** Begin file malloc.c ******************************************/
/*
** 2001 September 15
**
|
| ︙ | ︙ | |||
22420 22421 22422 22423 22424 22425 22426 |
testcase( c==(-1) );
testcase( c==0 );
testcase( c==(+1) );
}
return c;
}
| < | > | 22708 22709 22710 22711 22712 22713 22714 22715 22716 22717 22718 22719 22720 22721 22722 22723 22724 |
testcase( c==(-1) );
testcase( c==0 );
testcase( c==(+1) );
}
return c;
}
/*
** Convert zNum to a 64-bit signed integer. zNum must be decimal. This
** routine does *not* accept hexadecimal notation.
**
** If the zNum value is representable as a 64-bit twos-complement
** integer, then write that value into *pNum and return 0.
**
** If zNum is exactly 9223372036854775808, return 2. This special
** case is broken out because while 9223372036854775808 cannot be a
** signed 64-bit integer, its negative -9223372036854775808 can be.
|
| ︙ | ︙ | |||
22509 22510 22511 22512 22513 22514 22515 22516 22517 22518 22519 22520 22521 22522 22523 22524 22525 22526 22527 22528 22529 22530 22531 22532 22533 22534 |
/* zNum is exactly 9223372036854775808. Fits if negative. The
** special case 2 overflow if positive */
assert( u-1==LARGEST_INT64 );
return neg ? 0 : 2;
}
}
}
/*
** If zNum represents an integer that will fit in 32-bits, then set
** *pValue to that integer and return true. Otherwise return false.
**
** Any non-numeric characters that following zNum are ignored.
** This is different from sqlite3Atoi64() which requires the
** input number to be zero-terminated.
*/
SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
sqlite_int64 v = 0;
int i, c;
int neg = 0;
if( zNum[0]=='-' ){
neg = 1;
zNum++;
}else if( zNum[0]=='+' ){
zNum++;
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > | 22797 22798 22799 22800 22801 22802 22803 22804 22805 22806 22807 22808 22809 22810 22811 22812 22813 22814 22815 22816 22817 22818 22819 22820 22821 22822 22823 22824 22825 22826 22827 22828 22829 22830 22831 22832 22833 22834 22835 22836 22837 22838 22839 22840 22841 22842 22843 22844 22845 22846 22847 22848 22849 22850 22851 22852 22853 22854 22855 22856 22857 22858 22859 22860 22861 22862 22863 22864 22865 22866 22867 22868 22869 22870 22871 22872 22873 22874 22875 22876 22877 22878 22879 22880 22881 22882 |
/* zNum is exactly 9223372036854775808. Fits if negative. The
** special case 2 overflow if positive */
assert( u-1==LARGEST_INT64 );
return neg ? 0 : 2;
}
}
}
/*
** Transform a UTF-8 integer literal, in either decimal or hexadecimal,
** into a 64-bit signed integer. This routine accepts hexadecimal literals,
** whereas sqlite3Atoi64() does not.
**
** Returns:
**
** 0 Successful transformation. Fits in a 64-bit signed integer.
** 1 Integer too large for a 64-bit signed integer or is malformed
** 2 Special case of 9223372036854775808
*/
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
#ifndef SQLITE_OMIT_HEX_INTEGER
if( z[0]=='0'
&& (z[1]=='x' || z[1]=='X')
&& sqlite3Isxdigit(z[2])
){
u64 u = 0;
int i, k;
for(i=2; z[i]=='0'; i++){}
for(k=i; sqlite3Isxdigit(z[k]); k++){
u = u*16 + sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
return (z[k]==0 && k-i<=16) ? 0 : 1;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8);
}
}
/*
** If zNum represents an integer that will fit in 32-bits, then set
** *pValue to that integer and return true. Otherwise return false.
**
** This routine accepts both decimal and hexadecimal notation for integers.
**
** Any non-numeric characters that following zNum are ignored.
** This is different from sqlite3Atoi64() which requires the
** input number to be zero-terminated.
*/
SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
sqlite_int64 v = 0;
int i, c;
int neg = 0;
if( zNum[0]=='-' ){
neg = 1;
zNum++;
}else if( zNum[0]=='+' ){
zNum++;
}
#ifndef SQLITE_OMIT_HEX_INTEGER
else if( zNum[0]=='0'
&& (zNum[1]=='x' || zNum[1]=='X')
&& sqlite3Isxdigit(zNum[2])
){
u32 u = 0;
zNum += 2;
while( zNum[0]=='0' ) zNum++;
for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){
u = u*16 + sqlite3HexToInt(zNum[i]);
}
if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){
memcpy(pValue, &u, 4);
return 1;
}else{
return 0;
}
}
#endif
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
v = v*10 + c;
}
/* The longest decimal representation of a 32 bit integer is 10 digits:
**
** 1234567890
|
| ︙ | ︙ | |||
23604 23605 23606 23607 23608 23609 23610 |
/* 45 */ "IfNot" OpHelp(""),
/* 46 */ "Column" OpHelp("r[P3]=PX"),
/* 47 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
/* 48 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
/* 49 */ "Count" OpHelp("r[P2]=count()"),
/* 50 */ "ReadCookie" OpHelp(""),
/* 51 */ "SetCookie" OpHelp(""),
| > | | | | | | | | | | | | | | | | | | < > | | < | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < > | | | | | | | | < > | | | | | | | | | | | 23944 23945 23946 23947 23948 23949 23950 23951 23952 23953 23954 23955 23956 23957 23958 23959 23960 23961 23962 23963 23964 23965 23966 23967 23968 23969 23970 23971 23972 23973 23974 23975 23976 23977 23978 23979 23980 23981 23982 23983 23984 23985 23986 23987 23988 23989 23990 23991 23992 23993 23994 23995 23996 23997 23998 23999 24000 24001 24002 24003 24004 24005 24006 24007 24008 24009 24010 24011 24012 24013 24014 24015 24016 24017 24018 24019 24020 24021 24022 24023 24024 24025 24026 24027 24028 24029 24030 24031 24032 24033 24034 24035 24036 24037 24038 24039 24040 24041 24042 24043 24044 24045 24046 24047 24048 24049 24050 24051 24052 24053 24054 24055 24056 24057 24058 24059 24060 24061 24062 24063 24064 |
/* 45 */ "IfNot" OpHelp(""),
/* 46 */ "Column" OpHelp("r[P3]=PX"),
/* 47 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
/* 48 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
/* 49 */ "Count" OpHelp("r[P2]=count()"),
/* 50 */ "ReadCookie" OpHelp(""),
/* 51 */ "SetCookie" OpHelp(""),
/* 52 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
/* 53 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
/* 54 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
/* 55 */ "OpenAutoindex" OpHelp("nColumn=P2"),
/* 56 */ "OpenEphemeral" OpHelp("nColumn=P2"),
/* 57 */ "SorterOpen" OpHelp(""),
/* 58 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
/* 59 */ "Close" OpHelp(""),
/* 60 */ "SeekLT" OpHelp("key=r[P3@P4]"),
/* 61 */ "SeekLE" OpHelp("key=r[P3@P4]"),
/* 62 */ "SeekGE" OpHelp("key=r[P3@P4]"),
/* 63 */ "SeekGT" OpHelp("key=r[P3@P4]"),
/* 64 */ "Seek" OpHelp("intkey=r[P2]"),
/* 65 */ "NoConflict" OpHelp("key=r[P3@P4]"),
/* 66 */ "NotFound" OpHelp("key=r[P3@P4]"),
/* 67 */ "Found" OpHelp("key=r[P3@P4]"),
/* 68 */ "NotExists" OpHelp("intkey=r[P3]"),
/* 69 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
/* 70 */ "NewRowid" OpHelp("r[P2]=rowid"),
/* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
/* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
/* 73 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
/* 74 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
/* 75 */ "Delete" OpHelp(""),
/* 76 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
/* 77 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
/* 78 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"),
/* 79 */ "Eq" OpHelp("if r[P1]==r[P3] goto P2"),
/* 80 */ "Gt" OpHelp("if r[P1]>r[P3] goto P2"),
/* 81 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"),
/* 82 */ "Lt" OpHelp("if r[P1]<r[P3] goto P2"),
/* 83 */ "Ge" OpHelp("if r[P1]>=r[P3] goto P2"),
/* 84 */ "ResetCount" OpHelp(""),
/* 85 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
/* 86 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
/* 87 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
/* 88 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
/* 89 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
/* 90 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
/* 91 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
/* 92 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
/* 93 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
/* 94 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
/* 95 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
/* 96 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
/* 97 */ "String8" OpHelp("r[P2]='P4'"),
/* 98 */ "SorterData" OpHelp("r[P2]=data"),
/* 99 */ "RowKey" OpHelp("r[P2]=key"),
/* 100 */ "RowData" OpHelp("r[P2]=data"),
/* 101 */ "Rowid" OpHelp("r[P2]=rowid"),
/* 102 */ "NullRow" OpHelp(""),
/* 103 */ "Last" OpHelp(""),
/* 104 */ "SorterSort" OpHelp(""),
/* 105 */ "Sort" OpHelp(""),
/* 106 */ "Rewind" OpHelp(""),
/* 107 */ "SorterInsert" OpHelp(""),
/* 108 */ "IdxInsert" OpHelp("key=r[P2]"),
/* 109 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
/* 110 */ "IdxRowid" OpHelp("r[P2]=rowid"),
/* 111 */ "IdxLE" OpHelp("key=r[P3@P4]"),
/* 112 */ "IdxGT" OpHelp("key=r[P3@P4]"),
/* 113 */ "IdxLT" OpHelp("key=r[P3@P4]"),
/* 114 */ "IdxGE" OpHelp("key=r[P3@P4]"),
/* 115 */ "Destroy" OpHelp(""),
/* 116 */ "Clear" OpHelp(""),
/* 117 */ "ResetSorter" OpHelp(""),
/* 118 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
/* 119 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
/* 120 */ "ParseSchema" OpHelp(""),
/* 121 */ "LoadAnalysis" OpHelp(""),
/* 122 */ "DropTable" OpHelp(""),
/* 123 */ "DropIndex" OpHelp(""),
/* 124 */ "DropTrigger" OpHelp(""),
/* 125 */ "IntegrityCk" OpHelp(""),
/* 126 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
/* 127 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
/* 128 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
/* 129 */ "Program" OpHelp(""),
/* 130 */ "Param" OpHelp(""),
/* 131 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
/* 132 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
/* 133 */ "Real" OpHelp("r[P2]=P4"),
/* 134 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
/* 135 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
/* 136 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"),
/* 137 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
/* 138 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
/* 139 */ "IncrVacuum" OpHelp(""),
/* 140 */ "Expire" OpHelp(""),
/* 141 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
/* 142 */ "VBegin" OpHelp(""),
/* 143 */ "ToText" OpHelp(""),
/* 144 */ "ToBlob" OpHelp(""),
/* 145 */ "ToNumeric" OpHelp(""),
/* 146 */ "ToInt" OpHelp(""),
/* 147 */ "ToReal" OpHelp(""),
/* 148 */ "VCreate" OpHelp(""),
/* 149 */ "VDestroy" OpHelp(""),
/* 150 */ "VOpen" OpHelp(""),
/* 151 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
/* 152 */ "VNext" OpHelp(""),
/* 153 */ "VRename" OpHelp(""),
/* 154 */ "Pagecount" OpHelp(""),
/* 155 */ "MaxPgcnt" OpHelp(""),
/* 156 */ "Init" OpHelp("Start at P2"),
/* 157 */ "Noop" OpHelp(""),
/* 158 */ "Explain" OpHelp(""),
};
return azName[i];
}
#endif
/************** End of opcodes.c *********************************************/
/************** Begin file os_unix.c *****************************************/
|
| ︙ | ︙ | |||
23812 23813 23814 23815 23816 23817 23818 | #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> /* #include <time.h> */ #include <sys/time.h> #include <errno.h> #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 | | < | | 24153 24154 24155 24156 24157 24158 24159 24160 24161 24162 24163 24164 24165 24166 24167 24168 24169 24170 | #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> /* #include <time.h> */ #include <sys/time.h> #include <errno.h> #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 # include <sys/mman.h> #endif #if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS # include <sys/ioctl.h> # if OS_VXWORKS # include <semaphore.h> # include <limits.h> # else # include <sys/file.h> # include <sys/param.h> |
| ︙ | ︙ | |||
24244 24245 24246 24247 24248 24249 24250 24251 24252 24253 24254 24255 24256 24257 24258 |
/*
** On some systems, calls to fchown() will trigger a message in a security
** log if they come from non-root processes. So avoid calling fchown() if
** we are not running as root.
*/
static int posixFchown(int fd, uid_t uid, gid_t gid){
return geteuid() ? 0 : fchown(fd,uid,gid);
}
/* Forward reference */
static int openDirectory(const char*, int*);
static int unixGetpagesize(void);
/*
| > > > > | 24584 24585 24586 24587 24588 24589 24590 24591 24592 24593 24594 24595 24596 24597 24598 24599 24600 24601 24602 |
/*
** On some systems, calls to fchown() will trigger a message in a security
** log if they come from non-root processes. So avoid calling fchown() if
** we are not running as root.
*/
static int posixFchown(int fd, uid_t uid, gid_t gid){
#if OS_VXWORKS
return 0;
#else
return geteuid() ? 0 : fchown(fd,uid,gid);
#endif
}
/* Forward reference */
static int openDirectory(const char*, int*);
static int unixGetpagesize(void);
/*
|
| ︙ | ︙ | |||
24300 24301 24302 24303 24304 24305 24306 |
{ "fcntl", (sqlite3_syscall_ptr)fcntl, 0 },
#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent)
{ "read", (sqlite3_syscall_ptr)read, 0 },
#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
| | | | 24644 24645 24646 24647 24648 24649 24650 24651 24652 24653 24654 24655 24656 24657 24658 24659 24660 24661 24662 24663 24664 24665 24666 24667 24668 24669 24670 24671 24672 24673 24674 24675 |
{ "fcntl", (sqlite3_syscall_ptr)fcntl, 0 },
#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent)
{ "read", (sqlite3_syscall_ptr)read, 0 },
#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
{ "pread", (sqlite3_syscall_ptr)pread, 0 },
#else
{ "pread", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)
#if defined(USE_PREAD64)
{ "pread64", (sqlite3_syscall_ptr)pread64, 0 },
#else
{ "pread64", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
{ "write", (sqlite3_syscall_ptr)write, 0 },
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
{ "pwrite", (sqlite3_syscall_ptr)pwrite, 0 },
#else
{ "pwrite", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
aSyscall[12].pCurrent)
|
| ︙ | ︙ | |||
24687 24688 24689 24690 24691 24692 24693 |
(sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){
return SQLITE_BUSY;
}
/* else fall through */
case EPERM:
return SQLITE_PERM;
| < < < < < < < < < < | 25031 25032 25033 25034 25035 25036 25037 25038 25039 25040 25041 25042 25043 25044 |
(sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){
return SQLITE_BUSY;
}
/* else fall through */
case EPERM:
return SQLITE_PERM;
#if EOPNOTSUPP!=ENOTSUP
case EOPNOTSUPP:
/* something went terribly awry, unless during file system support
* introspection, in which it actually means what it says */
#endif
#ifdef ENOTSUP
case ENOTSUP:
|
| ︙ | ︙ | |||
25229 25230 25231 25232 25233 25234 25235 25236 25237 |
return SQLITE_OK;
}
/*
** Return TRUE if pFile has been renamed or unlinked since it was first opened.
*/
static int fileHasMoved(unixFile *pFile){
struct stat buf;
return pFile->pInode!=0 &&
| > > > | > | 25563 25564 25565 25566 25567 25568 25569 25570 25571 25572 25573 25574 25575 25576 25577 25578 25579 25580 25581 25582 25583 |
return SQLITE_OK;
}
/*
** Return TRUE if pFile has been renamed or unlinked since it was first opened.
*/
static int fileHasMoved(unixFile *pFile){
#if OS_VXWORKS
return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId;
#else
struct stat buf;
return pFile->pInode!=0 &&
(osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino);
#endif
}
/*
** Check a unixFile that is a database. Verify the following:
**
** (1) There is exactly one hard link on the file
|
| ︙ | ︙ | |||
26374 26375 26376 26377 26378 26379 26380 |
if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
/* Otherwise see if some other process holds it. */
if( !reserved ){
sem_t *pSem = pFile->pInode->pSem;
| < | 26712 26713 26714 26715 26716 26717 26718 26719 26720 26721 26722 26723 26724 26725 |
if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
/* Otherwise see if some other process holds it. */
if( !reserved ){
sem_t *pSem = pFile->pInode->pSem;
if( sem_trywait(pSem)==-1 ){
int tErrno = errno;
if( EAGAIN != tErrno ){
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
pFile->lastErrno = tErrno;
} else {
|
| ︙ | ︙ | |||
26427 26428 26429 26430 26431 26432 26433 |
** access the file.
**
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
static int semLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
| < | 26764 26765 26766 26767 26768 26769 26770 26771 26772 26773 26774 26775 26776 26777 |
** access the file.
**
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
static int semLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
sem_t *pSem = pFile->pInode->pSem;
int rc = SQLITE_OK;
/* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
if (pFile->eFileLock > NO_LOCK) {
pFile->eFileLock = eFileLock;
|
| ︙ | ︙ | |||
31711 31712 31713 31714 31715 31716 31717 | #endif #ifndef NTDDI_WINBLUE # define NTDDI_WINBLUE 0x06030000 #endif /* | | | < < < < | | | 32047 32048 32049 32050 32051 32052 32053 32054 32055 32056 32057 32058 32059 32060 32061 32062 32063 32064 32065 32066 32067 32068 | #endif #ifndef NTDDI_WINBLUE # define NTDDI_WINBLUE 0x06030000 #endif /* ** Check to see if the GetVersionEx[AW] functions are deprecated on the ** target system. GetVersionEx was first deprecated in Win8.1. */ #ifndef SQLITE_WIN32_GETVERSIONEX # if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE # define SQLITE_WIN32_GETVERSIONEX 0 /* GetVersionEx() is deprecated */ # else # define SQLITE_WIN32_GETVERSIONEX 1 /* GetVersionEx() is current */ # endif #endif /* ** This constant should already be defined (in the "WinDef.h" SDK file). */ #ifndef MAX_PATH |
| ︙ | ︙ | |||
31794 31795 31796 31797 31798 31799 31800 | #endif /* ** This macro is used when a local variable is set to a value that is ** [sometimes] not used by the code (e.g. via conditional compilation). */ #ifndef UNUSED_VARIABLE_VALUE | | | 32126 32127 32128 32129 32130 32131 32132 32133 32134 32135 32136 32137 32138 32139 32140 | #endif /* ** This macro is used when a local variable is set to a value that is ** [sometimes] not used by the code (e.g. via conditional compilation). */ #ifndef UNUSED_VARIABLE_VALUE # define UNUSED_VARIABLE_VALUE(x) (void)(x) #endif /* ** Returns the character that should be used as the directory separator. */ #ifndef winGetDirSep # define winGetDirSep() '\\' |
| ︙ | ︙ | |||
31843 31844 31845 31846 31847 31848 31849 | WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); #endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */ /* ** Some Microsoft compilers lack this definition. */ #ifndef INVALID_FILE_ATTRIBUTES | | | 32175 32176 32177 32178 32179 32180 32181 32182 32183 32184 32185 32186 32187 32188 32189 | WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); #endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */ /* ** Some Microsoft compilers lack this definition. */ #ifndef INVALID_FILE_ATTRIBUTES # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif #ifndef FILE_FLAG_MASK # define FILE_FLAG_MASK (0xFF3C0000) #endif #ifndef FILE_ATTRIBUTE_MASK |
| ︙ | ︙ | |||
31893 31894 31895 31896 31897 31898 31899 | #ifndef SQLITE_OMIT_WAL winShm *pShm; /* Instance of shared memory on this file */ #endif const char *zPath; /* Full pathname of this file */ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ #if SQLITE_OS_WINCE LPWSTR zDeleteOnClose; /* Name of file to delete when closing */ | | | 32225 32226 32227 32228 32229 32230 32231 32232 32233 32234 32235 32236 32237 32238 32239 | #ifndef SQLITE_OMIT_WAL winShm *pShm; /* Instance of shared memory on this file */ #endif const char *zPath; /* Full pathname of this file */ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ #if SQLITE_OS_WINCE LPWSTR zDeleteOnClose; /* Name of file to delete when closing */ HANDLE hMutex; /* Mutex used to control access to shared lock */ HANDLE hShared; /* Shared memory segment used for locking */ winceLock local; /* Locks obtained by this instance of winFile */ winceLock *shared; /* Global shared lock memory for the file */ #endif #if SQLITE_MAX_MMAP_SIZE>0 int nFetchOut; /* Number of outstanding xFetch references */ HANDLE hMap; /* Handle for accessing memory mapping */ |
| ︙ | ︙ | |||
32053 32054 32055 32056 32057 32058 32059 | ** 1: Operating system is Win9x. ** 2: Operating system is WinNT. ** ** In order to facilitate testing on a WinNT system, the test fixture ** can manually set this value to 1 to emulate Win98 behavior. */ #ifdef SQLITE_TEST | | | < | | 32385 32386 32387 32388 32389 32390 32391 32392 32393 32394 32395 32396 32397 32398 32399 32400 32401 | ** 1: Operating system is Win9x. ** 2: Operating system is WinNT. ** ** In order to facilitate testing on a WinNT system, the test fixture ** can manually set this value to 1 to emulate Win98 behavior. */ #ifdef SQLITE_TEST SQLITE_API LONG volatile sqlite3_os_type = 0; #else static LONG volatile sqlite3_os_type = 0; #endif #ifndef SYSCALL # define SYSCALL sqlite3_syscall_ptr #endif /* |
| ︙ | ︙ | |||
32687 32688 32689 32690 32691 32692 32693 32694 32695 32696 32697 32698 32699 32700 |
#else
{ "CreateFileMappingFromApp", (SYSCALL)0, 0 },
#endif
#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent)
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "win32" VFSes. Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
| > > > > > > > > > > > > > > > > | 33018 33019 33020 33021 33022 33023 33024 33025 33026 33027 33028 33029 33030 33031 33032 33033 33034 33035 33036 33037 33038 33039 33040 33041 33042 33043 33044 33045 33046 33047 |
#else
{ "CreateFileMappingFromApp", (SYSCALL)0, 0 },
#endif
#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent)
/*
** NOTE: On some sub-platforms, the InterlockedCompareExchange "function"
** is really just a macro that uses a compiler intrinsic (e.g. x64).
** So do not try to make this is into a redefinable interface.
*/
#if defined(InterlockedCompareExchange)
{ "InterlockedCompareExchange", (SYSCALL)0, 0 },
#define osInterlockedCompareExchange InterlockedCompareExchange
#else
{ "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*, \
LONG,LONG))aSyscall[76].pCurrent)
#endif /* defined(InterlockedCompareExchange) */
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "win32" VFSes. Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
|
| ︙ | ︙ | |||
32937 32938 32939 32940 32941 32942 32943 | #if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX # define osIsNT() (1) #elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) # define osIsNT() (1) #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) #else | > > | > > > > > > | > | | | | > > | | | | > > < | > > > > | < > | 33284 33285 33286 33287 33288 33289 33290 33291 33292 33293 33294 33295 33296 33297 33298 33299 33300 33301 33302 33303 33304 33305 33306 33307 33308 33309 33310 33311 33312 33313 33314 33315 33316 33317 33318 33319 33320 33321 33322 33323 33324 33325 33326 33327 33328 33329 |
#if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX
# define osIsNT() (1)
#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
# define osIsNT() (1)
#elif !defined(SQLITE_WIN32_HAS_WIDE)
# define osIsNT() (0)
#else
# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
#endif
/*
** This function determines if the machine is running a version of Windows
** based on the NT kernel.
*/
SQLITE_API int sqlite3_win32_is_nt(void){
#if defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8
OSVERSIONINFOW sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
osGetVersionExW(&sInfo);
osInterlockedCompareExchange(&sqlite3_os_type,
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
#elif defined(SQLITE_WIN32_HAS_ANSI)
OSVERSIONINFOA sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
osGetVersionExA(&sInfo);
osInterlockedCompareExchange(&sqlite3_os_type,
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
#endif
}
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#elif SQLITE_TEST
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#else
return 1;
#endif
}
#ifdef SQLITE_WIN32_MALLOC
/*
** Allocate nBytes of memory.
*/
static void *winMemMalloc(int nBytes){
HANDLE hHeap;
|
| ︙ | ︙ | |||
33160 33161 33162 33163 33164 33165 33166 |
SQLITE_PRIVATE void sqlite3MemSetDefault(void){
sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
}
#endif /* SQLITE_WIN32_MALLOC */
/*
| | | 33523 33524 33525 33526 33527 33528 33529 33530 33531 33532 33533 33534 33535 33536 33537 |
SQLITE_PRIVATE void sqlite3MemSetDefault(void){
sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
}
#endif /* SQLITE_WIN32_MALLOC */
/*
** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
**
** Space to hold the returned string is obtained from malloc.
*/
static LPWSTR winUtf8ToUnicode(const char *zFilename){
int nChar;
LPWSTR zWideFilename;
|
| ︙ | ︙ | |||
33213 33214 33215 33216 33217 33218 33219 | } return zFilename; } /* ** Convert an ANSI string to Microsoft Unicode, based on the ** current codepage settings for file apis. | | | 33576 33577 33578 33579 33580 33581 33582 33583 33584 33585 33586 33587 33588 33589 33590 |
}
return zFilename;
}
/*
** Convert an ANSI string to Microsoft Unicode, based on the
** current codepage settings for file apis.
**
** Space to hold the returned string is obtained
** from sqlite3_malloc.
*/
static LPWSTR winMbcsToUnicode(const char *zFilename){
int nByte;
LPWSTR zMbcsFilename;
int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
|
| ︙ | ︙ | |||
33287 33288 33289 33290 33291 33292 33293 | } zFilenameUtf8 = winUnicodeToUtf8(zTmpWide); sqlite3_free(zTmpWide); return zFilenameUtf8; } /* | | | 33650 33651 33652 33653 33654 33655 33656 33657 33658 33659 33660 33661 33662 33663 33664 |
}
zFilenameUtf8 = winUnicodeToUtf8(zTmpWide);
sqlite3_free(zTmpWide);
return zFilenameUtf8;
}
/*
** Convert UTF-8 to multibyte character string. Space to hold the
** returned string is obtained from sqlite3_malloc().
*/
SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
char *zFilenameMbcs;
LPWSTR zTmpWide;
zTmpWide = winUtf8ToUnicode(zFilename);
|
| ︙ | ︙ | |||
33427 33428 33429 33430 33431 33432 33433 | /* ** ** This function - winLogErrorAtLine() - is only ever called via the macro ** winLogError(). ** ** This routine is invoked after an error occurs in an OS function. ** It logs a message using sqlite3_log() containing the current value of | | | | 33790 33791 33792 33793 33794 33795 33796 33797 33798 33799 33800 33801 33802 33803 33804 33805 33806 33807 33808 | /* ** ** This function - winLogErrorAtLine() - is only ever called via the macro ** winLogError(). ** ** This routine is invoked after an error occurs in an OS function. ** It logs a message using sqlite3_log() containing the current value of ** error code and, if possible, the human-readable equivalent from ** FormatMessage. ** ** The first argument passed to the macro should be the error code that ** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). ** The two subsequent arguments should be the name of the OS function that ** failed and the associated file-system path, if any. */ #define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__) static int winLogErrorAtLine( int errcode, /* SQLite error code */ DWORD lastErrno, /* Win32 last error */ |
| ︙ | ︙ | |||
33462 33463 33464 33465 33466 33467 33468 | ); return errcode; } /* ** The number of times that a ReadFile(), WriteFile(), and DeleteFile() | | | 33825 33826 33827 33828 33829 33830 33831 33832 33833 33834 33835 33836 33837 33838 33839 | ); return errcode; } /* ** The number of times that a ReadFile(), WriteFile(), and DeleteFile() ** will be retried following a locking error - probably caused by ** antivirus software. Also the initial delay before the first retry. ** The delay increases linearly with each retry. */ #ifndef SQLITE_WIN32_IOERR_RETRY # define SQLITE_WIN32_IOERR_RETRY 10 #endif #ifndef SQLITE_WIN32_IOERR_RETRY_DELAY |
| ︙ | ︙ | |||
33537 33538 33539 33540 33541 33542 33543 |
}
/*
** Log a I/O error retry episode.
*/
static void winLogIoerr(int nRetry){
if( nRetry ){
| | | 33900 33901 33902 33903 33904 33905 33906 33907 33908 33909 33910 33911 33912 33913 33914 |
}
/*
** Log a I/O error retry episode.
*/
static void winLogIoerr(int nRetry){
if( nRetry ){
sqlite3_log(SQLITE_IOERR,
"delayed %dms for lock/sharing conflict",
winIoerrRetryDelay*nRetry*(nRetry+1)/2
);
}
}
#if SQLITE_OS_WINCE
|
| ︙ | ︙ | |||
33631 33632 33633 33634 33635 33636 33637 |
sqlite3_free(zName);
return winLogError(SQLITE_IOERR, pFile->lastErrno,
"winceCreateLock1", zFilename);
}
/* Acquire the mutex before continuing */
winceMutexAcquire(pFile->hMutex);
| | | | | | | 33994 33995 33996 33997 33998 33999 34000 34001 34002 34003 34004 34005 34006 34007 34008 34009 34010 34011 34012 34013 34014 34015 34016 34017 34018 34019 34020 34021 34022 34023 34024 34025 34026 34027 34028 34029 |
sqlite3_free(zName);
return winLogError(SQLITE_IOERR, pFile->lastErrno,
"winceCreateLock1", zFilename);
}
/* Acquire the mutex before continuing */
winceMutexAcquire(pFile->hMutex);
/* Since the names of named mutexes, semaphores, file mappings etc are
** case-sensitive, take advantage of that by uppercasing the mutex name
** and using that as the shared filemapping name.
*/
osCharUpperW(zName);
pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, sizeof(winceLock),
zName);
/* Set a flag that indicates we're the first to create the memory so it
** must be zero-initialized */
lastErrno = osGetLastError();
if (lastErrno == ERROR_ALREADY_EXISTS){
bInit = FALSE;
}
sqlite3_free(zName);
/* If we succeeded in making the shared memory handle, map it. */
if( pFile->hShared ){
pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
/* If mapping failed, close the shared memory handle and erase it */
if( !pFile->shared ){
pFile->lastErrno = osGetLastError();
winLogError(SQLITE_IOERR, pFile->lastErrno,
"winceCreateLock2", zFilename);
bLogged = TRUE;
|
| ︙ | ︙ | |||
33678 33679 33680 33681 33682 33683 33684 |
bLogged = TRUE;
}
winceMutexRelease(pFile->hMutex);
osCloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
return SQLITE_IOERR;
}
| | | 34041 34042 34043 34044 34045 34046 34047 34048 34049 34050 34051 34052 34053 34054 34055 |
bLogged = TRUE;
}
winceMutexRelease(pFile->hMutex);
osCloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
return SQLITE_IOERR;
}
/* Initialize the shared memory if we're supposed to */
if( bInit ){
memset(pFile->shared, 0, sizeof(winceLock));
}
winceMutexRelease(pFile->hMutex);
return SQLITE_OK;
|
| ︙ | ︙ | |||
33716 33717 33718 33719 33720 33721 33722 |
}
/* De-reference and close our copy of the shared memory handle */
osUnmapViewOfFile(pFile->shared);
osCloseHandle(pFile->hShared);
/* Done with the mutex */
| | | | 34079 34080 34081 34082 34083 34084 34085 34086 34087 34088 34089 34090 34091 34092 34093 34094 34095 34096 34097 34098 34099 |
}
/* De-reference and close our copy of the shared memory handle */
osUnmapViewOfFile(pFile->shared);
osCloseHandle(pFile->hShared);
/* Done with the mutex */
winceMutexRelease(pFile->hMutex);
osCloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
}
}
/*
** An implementation of the LockFile() API of Windows for CE
*/
static BOOL winceLockFile(
LPHANDLE phFile,
DWORD dwFileOffsetLow,
DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToLockLow,
|
| ︙ | ︙ | |||
33933 33934 33935 33936 33937 33938 33939 | ** Some Microsoft compilers lack this definition. */ #ifndef INVALID_SET_FILE_POINTER # define INVALID_SET_FILE_POINTER ((DWORD)-1) #endif /* | | | | | | | | 34296 34297 34298 34299 34300 34301 34302 34303 34304 34305 34306 34307 34308 34309 34310 34311 34312 34313 34314 34315 34316 34317 34318 34319 34320 34321 34322 34323 34324 34325 34326 34327 34328 34329 34330 |
** Some Microsoft compilers lack this definition.
*/
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
/*
** Move the current position of the file handle passed as the first
** argument to offset iOffset within the file. If successful, return 0.
** Otherwise, set pFile->lastErrno and return non-zero.
*/
static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
#if !SQLITE_OS_WINRT
LONG upperBits; /* Most sig. 32 bits of new offset */
LONG lowerBits; /* Least sig. 32 bits of new offset */
DWORD dwRet; /* Value returned by SetFilePointer() */
DWORD lastErrno; /* Value returned by GetLastError() */
OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
lowerBits = (LONG)(iOffset & 0xffffffff);
/* API oddity: If successful, SetFilePointer() returns a dword
** containing the lower 32-bits of the new file-offset. Or, if it fails,
** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
** whether an error has actually occurred, it is also necessary to call
** GetLastError().
*/
dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( (dwRet==INVALID_SET_FILE_POINTER
&& ((lastErrno = osGetLastError())!=NO_ERROR)) ){
pFile->lastErrno = lastErrno;
|
| ︙ | ︙ | |||
34036 34037 34038 34039 34040 34041 34042 |
#if SQLITE_OS_WINCE
#define WINCE_DELETION_ATTEMPTS 3
winceDestroyLock(pFile);
if( pFile->zDeleteOnClose ){
int cnt = 0;
while(
osDeleteFileW(pFile->zDeleteOnClose)==0
| | | 34399 34400 34401 34402 34403 34404 34405 34406 34407 34408 34409 34410 34411 34412 34413 |
#if SQLITE_OS_WINCE
#define WINCE_DELETION_ATTEMPTS 3
winceDestroyLock(pFile);
if( pFile->zDeleteOnClose ){
int cnt = 0;
while(
osDeleteFileW(pFile->zDeleteOnClose)==0
&& osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
&& cnt++ < WINCE_DELETION_ATTEMPTS
){
sqlite3_win32_sleep(100); /* Wait a little before trying again */
}
sqlite3_free(pFile->zDeleteOnClose);
}
#endif
|
| ︙ | ︙ | |||
34884 34885 34886 34887 34888 34889 34890 |
*/
static int winDeviceCharacteristics(sqlite3_file *id){
winFile *p = (winFile*)id;
return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
}
| | | | | | 35247 35248 35249 35250 35251 35252 35253 35254 35255 35256 35257 35258 35259 35260 35261 35262 35263 35264 35265 35266 35267 35268 35269 35270 35271 35272 35273 35274 35275 35276 35277 |
*/
static int winDeviceCharacteristics(sqlite3_file *id){
winFile *p = (winFile*)id;
return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
}
/*
** Windows will only let you create file view mappings
** on allocation size granularity boundaries.
** During sqlite3_os_init() we do a GetSystemInfo()
** to get the granularity size.
*/
static SYSTEM_INFO winSysInfo;
#ifndef SQLITE_OMIT_WAL
/*
** Helper functions to obtain and relinquish the global mutex. The
** global mutex is used to protect the winLockInfo objects used by
** this file, all of which may be shared by multiple threads.
**
** Function winShmMutexHeld() is used to assert() that the global mutex
** is held when required. This function is only used as part of assert()
** statements. e.g.
**
** winShmEnterMutex()
** assert( winShmMutexHeld() );
** winShmLeaveMutex()
*/
static void winShmEnterMutex(void){
|
| ︙ | ︙ | |||
34930 34931 34932 34933 34934 34935 34936 | ** point to a single instance of this object. In other words, each ** log-summary is opened only once per process. ** ** winShmMutexHeld() must be true when creating or destroying ** this object or while reading or writing the following fields: ** ** nRef | | | | 35293 35294 35295 35296 35297 35298 35299 35300 35301 35302 35303 35304 35305 35306 35307 35308 35309 35310 | ** point to a single instance of this object. In other words, each ** log-summary is opened only once per process. ** ** winShmMutexHeld() must be true when creating or destroying ** this object or while reading or writing the following fields: ** ** nRef ** pNext ** ** The following fields are read-only after the object is created: ** ** fid ** zFilename ** ** Either winShmNode.mutex must be held or winShmNode.nRef==0 and ** winShmMutexHeld() is true when reading or writing any other field ** in this structure. ** |
| ︙ | ︙ | |||
35029 35030 35031 35032 35033 35034 35035 |
rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
}else{
/* Initialize the locking parameters */
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
}
| | | 35392 35393 35394 35395 35396 35397 35398 35399 35400 35401 35402 35403 35404 35405 35406 |
rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
}else{
/* Initialize the locking parameters */
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
}
if( rc!= 0 ){
rc = SQLITE_OK;
}else{
pFile->lastErrno = osGetLastError();
rc = SQLITE_BUSY;
}
|
| ︙ | ︙ | |||
35125 35126 35127 35128 35129 35130 35131 |
pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
if( pNew==0 ){
sqlite3_free(p);
return SQLITE_IOERR_NOMEM;
}
pNew->zFilename = (char*)&pNew[1];
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
| | | 35488 35489 35490 35491 35492 35493 35494 35495 35496 35497 35498 35499 35500 35501 35502 |
pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
if( pNew==0 ){
sqlite3_free(p);
return SQLITE_IOERR_NOMEM;
}
pNew->zFilename = (char*)&pNew[1];
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
/* Look to see if there is an existing winShmNode that can be used.
** If no matching winShmNode currently exists, create a new one.
*/
winShmEnterMutex();
for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
/* TBD need to come up with better match here. Perhaps
|
| ︙ | ︙ | |||
35162 35163 35164 35165 35166 35167 35168 |
SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
0);
if( SQLITE_OK!=rc ){
goto shm_open_err;
}
/* Check to see if another process is holding the dead-man switch.
| | | 35525 35526 35527 35528 35529 35530 35531 35532 35533 35534 35535 35536 35537 35538 35539 |
SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
0);
if( SQLITE_OK!=rc ){
goto shm_open_err;
}
/* Check to see if another process is holding the dead-man switch.
** If not, truncate the file to zero length.
*/
if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
if( rc!=SQLITE_OK ){
rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
"winOpenShm", pDbFd->zPath);
}
|
| ︙ | ︙ | |||
35191 35192 35193 35194 35195 35196 35197 | pDbFd->pShm = p; winShmLeaveMutex(); /* The reference count on pShmNode has already been incremented under ** the cover of the winShmEnterMutex() mutex and the pointer from the ** new (struct winShm) object to the pShmNode has been set. All that is ** left to do is to link the new object into the linked list starting | | | | 35554 35555 35556 35557 35558 35559 35560 35561 35562 35563 35564 35565 35566 35567 35568 35569 35570 35571 35572 35573 35574 35575 35576 35577 35578 35579 35580 35581 35582 35583 35584 35585 35586 35587 35588 |
pDbFd->pShm = p;
winShmLeaveMutex();
/* The reference count on pShmNode has already been incremented under
** the cover of the winShmEnterMutex() mutex and the pointer from the
** new (struct winShm) object to the pShmNode has been set. All that is
** left to do is to link the new object into the linked list starting
** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
** mutex.
*/
sqlite3_mutex_enter(pShmNode->mutex);
p->pNext = pShmNode->pFirst;
pShmNode->pFirst = p;
sqlite3_mutex_leave(pShmNode->mutex);
return SQLITE_OK;
/* Jump here on any error */
shm_open_err:
winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
sqlite3_free(p);
sqlite3_free(pNew);
winShmLeaveMutex();
return rc;
}
/*
** Close a connection to shared-memory. Delete the underlying
** storage if deleteFlag is true.
*/
static int winShmUnmap(
sqlite3_file *fd, /* Database holding shared memory */
int deleteFlag /* Delete after closing if true */
){
winFile *pDbFd; /* Database holding shared-memory */
|
| ︙ | ︙ | |||
35300 35301 35302 35303 35304 35305 35306 |
rc = SQLITE_OK;
}
/* Undo the local locks */
if( rc==SQLITE_OK ){
p->exclMask &= ~mask;
p->sharedMask &= ~mask;
| | | 35663 35664 35665 35666 35667 35668 35669 35670 35671 35672 35673 35674 35675 35676 35677 |
rc = SQLITE_OK;
}
/* Undo the local locks */
if( rc==SQLITE_OK ){
p->exclMask &= ~mask;
p->sharedMask &= ~mask;
}
}else if( flags & SQLITE_SHM_SHARED ){
u16 allShared = 0; /* Union of locks held by connections other than "p" */
/* Find out which shared locks are already held by sibling connections.
** If any sibling already holds an exclusive lock, go ahead and return
** SQLITE_BUSY.
*/
|
| ︙ | ︙ | |||
35339 35340 35341 35342 35343 35344 35345 |
*/
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
rc = SQLITE_BUSY;
break;
}
}
| | | | | | | | | | | 35702 35703 35704 35705 35706 35707 35708 35709 35710 35711 35712 35713 35714 35715 35716 35717 35718 35719 35720 35721 35722 35723 35724 35725 35726 35727 35728 35729 35730 35731 35732 35733 35734 35735 35736 35737 35738 35739 35740 35741 35742 35743 35744 35745 35746 35747 35748 35749 35750 35751 35752 35753 35754 35755 35756 35757 35758 35759 35760 35761 35762 35763 35764 35765 35766 |
*/
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
rc = SQLITE_BUSY;
break;
}
}
/* Get the exclusive locks at the system level. Then if successful
** also mark the local connection as being locked.
*/
if( rc==SQLITE_OK ){
rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
if( rc==SQLITE_OK ){
assert( (p->sharedMask & mask)==0 );
p->exclMask |= mask;
}
}
}
sqlite3_mutex_leave(pShmNode->mutex);
OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
sqlite3ErrName(rc)));
return rc;
}
/*
** Implement a memory barrier or memory fence on shared memory.
**
** All loads and stores begun before the barrier must complete before
** any load or store begun after the barrier.
*/
static void winShmBarrier(
sqlite3_file *fd /* Database holding the shared memory */
){
UNUSED_PARAMETER(fd);
/* MemoryBarrier(); // does not work -- do not know why not */
winShmEnterMutex();
winShmLeaveMutex();
}
/*
** This function is called to obtain a pointer to region iRegion of the
** shared-memory associated with the database file fd. Shared-memory regions
** are numbered starting from zero. Each shared-memory region is szRegion
** bytes in size.
**
** If an error occurs, an error code is returned and *pp is set to NULL.
**
** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
** region has not been allocated (by any client, including one running in a
** separate process), then *pp is set to NULL and SQLITE_OK returned. If
** isWrite is non-zero and the requested shared-memory region has not yet
** been allocated, it is allocated by this function.
**
** If the shared-memory region has already been allocated or is allocated by
** this call as described above, then it is mapped into this processes
** address space (if it is not already), *pp is set to point to the mapped
** memory and SQLITE_OK returned.
*/
static int winShmMap(
sqlite3_file *fd, /* Handle open on database file */
int iRegion, /* Region to retrieve */
int szRegion, /* Size of regions */
int isWrite, /* True to extend file if necessary */
|
| ︙ | ︙ | |||
35461 35462 35463 35464 35465 35466 35467 |
goto shmpage_out;
}
pShmNode->aRegion = apNew;
while( pShmNode->nRegion<=iRegion ){
HANDLE hMap = NULL; /* file-mapping handle */
void *pMap = 0; /* Mapped memory region */
| | | | | 35824 35825 35826 35827 35828 35829 35830 35831 35832 35833 35834 35835 35836 35837 35838 35839 35840 35841 35842 35843 35844 35845 35846 35847 35848 |
goto shmpage_out;
}
pShmNode->aRegion = apNew;
while( pShmNode->nRegion<=iRegion ){
HANDLE hMap = NULL; /* file-mapping handle */
void *pMap = 0; /* Mapped memory region */
#if SQLITE_OS_WINRT
hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
NULL, PAGE_READWRITE, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_WIDE)
hMap = osCreateFileMappingW(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_ANSI)
hMap = osCreateFileMappingA(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
);
#endif
OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
osGetCurrentProcessId(), pShmNode->nRegion, nByte,
hMap ? "ok" : "failed"));
if( hMap ){
|
| ︙ | ︙ | |||
35568 35569 35570 35571 35572 35573 35574 |
OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile));
return SQLITE_OK;
}
/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
| | | | | | | 35931 35932 35933 35934 35935 35936 35937 35938 35939 35940 35941 35942 35943 35944 35945 35946 35947 35948 35949 35950 35951 35952 |
OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile));
return SQLITE_OK;
}
/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
** is already mapped, the existing mapping is replaced by the new). Or, if
** there already exists a mapping for this file, and there are still
** outstanding xFetch() references to it, this function is a no-op.
**
** If parameter nByte is non-negative, then it is the requested size of
** the mapping to create. Otherwise, if nByte is less than zero, then the
** requested size is the size of the file on disk. The actual size of the
** created mapping is either the requested size or the value configured
** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller.
**
** SQLITE_OK is returned if no error occurs (even if the mapping is not
** recreated as a result of outstanding references) or an SQLite error
** code otherwise.
*/
static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
|
| ︙ | ︙ | |||
35604 35605 35606 35607 35608 35609 35610 |
return SQLITE_IOERR_FSTAT;
}
}
if( nMap>pFd->mmapSizeMax ){
nMap = pFd->mmapSizeMax;
}
nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
| | | 35967 35968 35969 35970 35971 35972 35973 35974 35975 35976 35977 35978 35979 35980 35981 |
return SQLITE_IOERR_FSTAT;
}
}
if( nMap>pFd->mmapSizeMax ){
nMap = pFd->mmapSizeMax;
}
nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
if( nMap==0 && pFd->mmapSize>0 ){
winUnmapfile(pFd);
}
if( nMap!=pFd->mmapSize ){
void *pNew = 0;
DWORD protect = PAGE_READONLY;
DWORD flags = FILE_MAP_READ;
|
| ︙ | ︙ | |||
35676 35677 35678 35679 35680 35681 35682 | ** iOff. The mapping must be valid for at least nAmt bytes. ** ** If such a pointer can be obtained, store it in *pp and return SQLITE_OK. ** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK. ** Finally, if an error does occur, return an SQLite error code. The final ** value of *pp is undefined in this case. ** | | | 36039 36040 36041 36042 36043 36044 36045 36046 36047 36048 36049 36050 36051 36052 36053 |
** iOff. The mapping must be valid for at least nAmt bytes.
**
** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
** If this function does return a pointer, the caller must eventually
** release the reference by calling winUnfetch().
*/
static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
winFile *pFd = (winFile*)fd; /* The underlying database file */
#endif
*pp = 0;
|
| ︙ | ︙ | |||
35711 35712 35713 35714 35715 35716 35717 |
OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), fd, pp, *pp));
return SQLITE_OK;
}
/*
| | | | | | | 36074 36075 36076 36077 36078 36079 36080 36081 36082 36083 36084 36085 36086 36087 36088 36089 36090 36091 36092 36093 36094 36095 36096 36097 36098 36099 36100 36101 |
OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), fd, pp, *pp));
return SQLITE_OK;
}
/*
** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to winFetch(). The second
** argument passed to this function must be the same as the corresponding
** argument that was passed to the winFetch() invocation.
**
** Or, if the third argument is NULL, then this function is being called
** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
#if SQLITE_MAX_MMAP_SIZE>0
winFile *pFd = (winFile*)fd; /* The underlying database file */
/* If p==0 (unmap the entire file) then there must be no outstanding
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
** then there must be at least one outstanding. */
assert( (p==0)==(pFd->nFetchOut==0) );
/* If p!=0, it must match the iOff value. */
assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
|
| ︙ | ︙ | |||
35870 35871 35872 35873 35874 35875 35876 | size_t i, j; int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX); int nMax, nBuf, nDir, nLen; char *zBuf; /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this | | | 36233 36234 36235 36236 36237 36238 36239 36240 36241 36242 36243 36244 36245 36246 36247 | size_t i, j; int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX); int nMax, nBuf, nDir, nLen; char *zBuf; /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. */ SimulateIOError( return SQLITE_IOERR ); /* Allocate a temporary buffer to store the fully qualified file ** name for the temporary file. If this fails, we cannot continue. */ nMax = pVfs->mxPathname; nBuf = nMax + 2; |
| ︙ | ︙ | |||
36052 36053 36054 36055 36056 36057 36058 |
if( !winMakeEndInDirSep(nDir+1, zBuf) ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
return winLogError(SQLITE_ERROR, 0, "winGetTempname4", 0);
}
/*
| | | 36415 36416 36417 36418 36419 36420 36421 36422 36423 36424 36425 36426 36427 36428 36429 |
if( !winMakeEndInDirSep(nDir+1, zBuf) ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
return winLogError(SQLITE_ERROR, 0, "winGetTempname4", 0);
}
/*
** Check that the output buffer is large enough for the temporary file
** name in the following format:
**
** "<temporary_directory>/etilqs_XXXXXXXXXXXXXXX\0\0"
**
** If not, return SQLITE_ERROR. The number 17 is used here in order to
** account for the space used by the 15 character random suffix and the
** two trailing NUL characters. The final directory separator character
|
| ︙ | ︙ | |||
36155 36156 36157 36158 36159 36160 36161 | int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); int isReadonly = (flags & SQLITE_OPEN_READONLY); int isReadWrite = (flags & SQLITE_OPEN_READWRITE); #ifndef NDEBUG int isOpenJournal = (isCreate && ( | | | | | | | | | | | | 36518 36519 36520 36521 36522 36523 36524 36525 36526 36527 36528 36529 36530 36531 36532 36533 36534 36535 36536 36537 36538 36539 36540 36541 36542 36543 36544 36545 36546 36547 36548 36549 36550 36551 36552 36553 36554 36555 36556 36557 36558 36559 36560 36561 36562 36563 36564 36565 36566 36567 36568 36569 36570 36571 36572 36573 36574 36575 36576 36577 36578 36579 |
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
int isCreate = (flags & SQLITE_OPEN_CREATE);
int isReadonly = (flags & SQLITE_OPEN_READONLY);
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
#ifndef NDEBUG
int isOpenJournal = (isCreate && (
eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
#endif
OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n",
zUtf8Name, id, flags, pOutFlags));
/* Check the following statements are true:
**
** (a) Exactly one of the READWRITE and READONLY flags must be set, and
** (b) if CREATE is set, then READWRITE must also be set, and
** (c) if EXCLUSIVE is set, then CREATE must also be set.
** (d) if DELETEONCLOSE is set, then CREATE must also be set.
*/
assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
assert(isCreate==0 || isReadWrite);
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
/* The main DB, main journal, WAL file and master journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
|| eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
assert( pFile!=0 );
memset(pFile, 0, sizeof(winFile));
pFile->h = INVALID_HANDLE_VALUE;
#if SQLITE_OS_WINRT
if( !zUtf8Name && !sqlite3_temp_directory ){
sqlite3_log(SQLITE_ERROR,
"sqlite3_temp_directory variable should be set for WinRT");
}
#endif
/* If the second argument to this function is NULL, generate a
** temporary file name to use
*/
if( !zUtf8Name ){
assert( isDelete && !isOpenJournal );
rc = winGetTempname(pVfs, &zTmpname);
if( rc!=SQLITE_OK ){
OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
return rc;
|
| ︙ | ︙ | |||
36242 36243 36244 36245 36246 36247 36248 |
if( isReadWrite ){
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
}else{
dwDesiredAccess = GENERIC_READ;
}
| | | | 36605 36606 36607 36608 36609 36610 36611 36612 36613 36614 36615 36616 36617 36618 36619 36620 |
if( isReadWrite ){
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
}else{
dwDesiredAccess = GENERIC_READ;
}
/* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
** created. SQLite doesn't use it to indicate "exclusive access"
** as it is usually understood.
*/
if( isExclusive ){
/* Creates a new file, only if it does not already exist. */
/* If the file exists, it fails. */
dwCreationDisposition = CREATE_NEW;
}else if( isCreate ){
|
| ︙ | ︙ | |||
36332 36333 36334 36335 36336 36337 36338 |
if( h==INVALID_HANDLE_VALUE ){
pFile->lastErrno = lastErrno;
winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
sqlite3_free(zConverted);
sqlite3_free(zTmpname);
if( isReadWrite && !isExclusive ){
| | | 36695 36696 36697 36698 36699 36700 36701 36702 36703 36704 36705 36706 36707 36708 36709 |
if( h==INVALID_HANDLE_VALUE ){
pFile->lastErrno = lastErrno;
winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
sqlite3_free(zConverted);
sqlite3_free(zTmpname);
if( isReadWrite && !isExclusive ){
return winOpen(pVfs, zName, id,
((flags|SQLITE_OPEN_READONLY) &
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
pOutFlags);
}else{
return SQLITE_CANTOPEN_BKPT;
}
}
|
| ︙ | ︙ | |||
36541 36542 36543 36544 36545 36546 36547 |
return SQLITE_IOERR_NOMEM;
}
if( osIsNT() ){
int cnt = 0;
WIN32_FILE_ATTRIBUTE_DATA sAttrData;
memset(&sAttrData, 0, sizeof(sAttrData));
while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
| | | | 36904 36905 36906 36907 36908 36909 36910 36911 36912 36913 36914 36915 36916 36917 36918 36919 36920 36921 36922 36923 36924 36925 |
return SQLITE_IOERR_NOMEM;
}
if( osIsNT() ){
int cnt = 0;
WIN32_FILE_ATTRIBUTE_DATA sAttrData;
memset(&sAttrData, 0, sizeof(sAttrData));
while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
GetFileExInfoStandard,
&sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
if( rc ){
/* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
** as if it does not exist.
*/
if( flags==SQLITE_ACCESS_EXISTS
&& sAttrData.nFileSizeHigh==0
&& sAttrData.nFileSizeLow==0 ){
attr = INVALID_FILE_ATTRIBUTES;
}else{
attr = sAttrData.dwFileAttributes;
}
}else{
winLogIoerr(cnt);
|
| ︙ | ︙ | |||
36647 36648 36649 36650 36651 36652 36653 |
*/
static int winFullPathname(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
| | | 37010 37011 37012 37013 37014 37015 37016 37017 37018 37019 37020 37021 37022 37023 37024 |
*/
static int winFullPathname(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
#if defined(__CYGWIN__)
SimulateIOError( return SQLITE_ERROR );
UNUSED_PARAMETER(nFull);
assert( nFull>=pVfs->mxPathname );
if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
/*
** NOTE: We are dealing with a relative path name and the data
|
| ︙ | ︙ | |||
36960 36961 36962 36963 36964 36965 36966 | /* ** Find the current time (in Universal Coordinated Time). Write into *piNow ** the current time and date as a Julian Day number times 86_400_000. In ** other words, write into *piNow the number of milliseconds since the Julian ** epoch of noon in Greenwich on November 24, 4714 B.C according to the ** proleptic Gregorian calendar. ** | | | | | | | 37323 37324 37325 37326 37327 37328 37329 37330 37331 37332 37333 37334 37335 37336 37337 37338 37339 37340 37341 37342 37343 37344 37345 37346 37347 37348 37349 37350 37351 37352 37353 37354 37355 37356 37357 37358 37359 37360 37361 37362 37363 37364 37365 37366 |
/*
** Find the current time (in Universal Coordinated Time). Write into *piNow
** the current time and date as a Julian Day number times 86_400_000. In
** other words, write into *piNow the number of milliseconds since the Julian
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
** proleptic Gregorian calendar.
**
** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
** cannot be found.
*/
static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
/* FILETIME structure is a 64-bit value representing the number of
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
*/
FILETIME ft;
static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
#ifdef SQLITE_TEST
static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
#endif
/* 2^32 - to avoid use of LL and warnings in gcc */
static const sqlite3_int64 max32BitValue =
(sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 +
(sqlite3_int64)294967296;
#if SQLITE_OS_WINCE
SYSTEMTIME time;
osGetSystemTime(&time);
/* if SystemTimeToFileTime() fails, it returns zero. */
if (!osSystemTimeToFileTime(&time,&ft)){
return SQLITE_ERROR;
}
#else
osGetSystemTimeAsFileTime( &ft );
#endif
*piNow = winFiletimeEpoch +
((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
(sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
*piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
}
#endif
|
| ︙ | ︙ | |||
37108 37109 37110 37111 37112 37113 37114 |
winGetSystemCall, /* xGetSystemCall */
winNextSystemCall, /* xNextSystemCall */
};
#endif
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
| | | | | 37471 37472 37473 37474 37475 37476 37477 37478 37479 37480 37481 37482 37483 37484 37485 37486 37487 37488 37489 37490 37491 37492 37493 37494 37495 37496 37497 37498 37499 37500 37501 37502 37503 37504 37505 37506 |
winGetSystemCall, /* xGetSystemCall */
winNextSystemCall, /* xNextSystemCall */
};
#endif
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==77 );
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
#if SQLITE_OS_WINRT
osGetNativeSystemInfo(&winSysInfo);
#else
osGetSystemInfo(&winSysInfo);
#endif
assert( winSysInfo.dwAllocationGranularity>0 );
assert( winSysInfo.dwPageSize>0 );
sqlite3_vfs_register(&winVfs, 1);
#if defined(SQLITE_WIN32_HAS_WIDE)
sqlite3_vfs_register(&winLongPathVfs, 0);
#endif
return SQLITE_OK;
}
SQLITE_API int sqlite3_os_end(void){
#if SQLITE_OS_WINRT
if( sleepObj!=NULL ){
osCloseHandle(sleepObj);
sleepObj = NULL;
}
#endif
return SQLITE_OK;
|
| ︙ | ︙ | |||
51330 51331 51332 51333 51334 51335 51336 | } /* If the client is reading or writing an index and the schema is ** not loaded, then it is too difficult to actually check to see if ** the correct locks are held. So do not bother - just return true. ** This case does not come up very often anyhow. */ | | | 51693 51694 51695 51696 51697 51698 51699 51700 51701 51702 51703 51704 51705 51706 51707 |
}
/* If the client is reading or writing an index and the schema is
** not loaded, then it is too difficult to actually check to see if
** the correct locks are held. So do not bother - just return true.
** This case does not come up very often anyhow.
*/
if( isIndex && (!pSchema || (pSchema->schemaFlags&DB_SchemaLoaded)==0) ){
return 1;
}
/* Figure out the root-page that the lock should be held on. For table
** b-trees, this is just the root page of the b-tree being read or
** written. For index b-trees, it is the root page of the associated
** table. */
|
| ︙ | ︙ | |||
52800 52801 52802 52803 52804 52805 52806 |
*/
static Pgno btreePagecount(BtShared *pBt){
return pBt->nPage;
}
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
assert( ((p->pBt->nPage)&0x8000000)==0 );
| | | 53163 53164 53165 53166 53167 53168 53169 53170 53171 53172 53173 53174 53175 53176 53177 |
*/
static Pgno btreePagecount(BtShared *pBt){
return pBt->nPage;
}
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
assert( ((p->pBt->nPage)&0x8000000)==0 );
return btreePagecount(p->pBt);
}
/*
** Get a page from the pager and initialize it. This routine is just a
** convenience wrapper around separate calls to btreeGetPage() and
** btreeInitPage().
**
|
| ︙ | ︙ | |||
61926 61927 61928 61929 61930 61931 61932 | zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; pB->isPrepareV2 = pA->isPrepareV2; } /* | | > | | | > > > > > > > > > > > > > > > > | 62289 62290 62291 62292 62293 62294 62295 62296 62297 62298 62299 62300 62301 62302 62303 62304 62305 62306 62307 62308 62309 62310 62311 62312 62313 62314 62315 62316 62317 62318 62319 62320 62321 62322 62323 62324 62325 62326 62327 62328 62329 62330 62331 |
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
pB->isPrepareV2 = pA->isPrepareV2;
}
/*
** Resize the Vdbe.aOp array so that it is at least nOp elements larger
** than its current size. nOp is guaranteed to be less than or equal
** to 1024/sizeof(Op).
**
** If an out-of-memory error occurs while resizing the array, return
** SQLITE_NOMEM. In this case Vdbe.aOp and Parse.nOpAlloc remain
** unchanged (this is so that any opcodes already allocated can be
** correctly deallocated along with the rest of the Vdbe).
*/
static int growOpArray(Vdbe *v, int nOp){
VdbeOp *pNew;
Parse *p = v->pParse;
/* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force
** more frequent reallocs and hence provide more opportunities for
** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used
** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array
** by the minimum* amount required until the size reaches 512. Normal
** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current
** size of the op array or add 1KB of space, whichever is smaller. */
#ifdef SQLITE_TEST_REALLOC_STRESS
int nNew = (p->nOpAlloc>=512 ? p->nOpAlloc*2 : p->nOpAlloc+nOp);
#else
int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op)));
UNUSED_PARAMETER(nOp);
#endif
assert( nOp<=(1024/sizeof(Op)) );
assert( nNew>=(p->nOpAlloc+nOp) );
pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op));
if( pNew ){
p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op);
v->aOp = pNew;
}
return (pNew ? SQLITE_OK : SQLITE_NOMEM);
}
|
| ︙ | ︙ | |||
61981 61982 61983 61984 61985 61986 61987 |
int i;
VdbeOp *pOp;
i = p->nOp;
assert( p->magic==VDBE_MAGIC_INIT );
assert( op>0 && op<0xff );
if( p->pParse->nOpAlloc<=i ){
| | | 62361 62362 62363 62364 62365 62366 62367 62368 62369 62370 62371 62372 62373 62374 62375 |
int i;
VdbeOp *pOp;
i = p->nOp;
assert( p->magic==VDBE_MAGIC_INIT );
assert( op>0 && op<0xff );
if( p->pParse->nOpAlloc<=i ){
if( growOpArray(p, 1) ){
return 1;
}
}
p->nOp++;
pOp = &p->aOp[i];
pOp->opcode = (u8)op;
pOp->p5 = 0;
|
| ︙ | ︙ | |||
62341 62342 62343 62344 62345 62346 62347 |
pOp->p2 = aLabel[-1-pOp->p2];
}
}
sqlite3DbFree(p->db, pParse->aLabel);
pParse->aLabel = 0;
pParse->nLabel = 0;
*pMaxFuncArgs = nMaxArgs;
| | | 62721 62722 62723 62724 62725 62726 62727 62728 62729 62730 62731 62732 62733 62734 62735 |
pOp->p2 = aLabel[-1-pOp->p2];
}
}
sqlite3DbFree(p->db, pParse->aLabel);
pParse->aLabel = 0;
pParse->nLabel = 0;
*pMaxFuncArgs = nMaxArgs;
assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
}
/*
** Return the address of the next instruction to be inserted.
*/
SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
assert( p->magic==VDBE_MAGIC_INIT );
|
| ︙ | ︙ | |||
62368 62369 62370 62371 62372 62373 62374 |
** returned program.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
VdbeOp *aOp = p->aOp;
assert( aOp && !p->db->mallocFailed );
/* Check that sqlite3VdbeUsesBtree() was not called on this VM */
| | | | 62748 62749 62750 62751 62752 62753 62754 62755 62756 62757 62758 62759 62760 62761 62762 62763 62764 62765 62766 62767 62768 62769 62770 62771 62772 62773 62774 62775 62776 62777 |
** returned program.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
VdbeOp *aOp = p->aOp;
assert( aOp && !p->db->mallocFailed );
/* Check that sqlite3VdbeUsesBtree() was not called on this VM */
assert( DbMaskAllZero(p->btreeMask) );
resolveP2Values(p, pnMaxArg);
*pnOp = p->nOp;
p->aOp = 0;
return aOp;
}
/*
** Add a whole list of operations to the operation stack. Return the
** address of the first operation added.
*/
SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
int addr;
assert( p->magic==VDBE_MAGIC_INIT );
if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
return 0;
}
addr = p->nOp;
if( ALWAYS(nOp>0) ){
int i;
VdbeOpList const *pIn = aOp;
for(i=0; i<nOp; i++, pIn++){
|
| ︙ | ︙ | |||
62568 62569 62570 62571 62572 62573 62574 |
pVdbe->pProgram = p;
}
/*
** Change the opcode at addr into OP_Noop
*/
SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
| | | 62948 62949 62950 62951 62952 62953 62954 62955 62956 62957 62958 62959 62960 62961 62962 |
pVdbe->pProgram = p;
}
/*
** Change the opcode at addr into OP_Noop
*/
SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
if( addr<p->nOp ){
VdbeOp *pOp = &p->aOp[addr];
sqlite3 *db = p->db;
freeP4(db, pOp->p4type, pOp->p4.p);
memset(pOp, 0, sizeof(pOp[0]));
pOp->opcode = OP_Noop;
if( addr==p->nOp-1 ) p->nOp--;
}
|
| ︙ | ︙ | |||
62953 62954 62955 62956 62957 62958 62959 |
** attached databases that will be use. A mask of these databases
** is maintained in p->btreeMask. The p->lockMask value is the subset of
** p->btreeMask of databases that will require a lock.
*/
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
assert( i>=0 && i<p->db->nDb && i<(int)sizeof(yDbMask)*8 );
assert( i<(int)sizeof(p->btreeMask)*8 );
| | | | 63333 63334 63335 63336 63337 63338 63339 63340 63341 63342 63343 63344 63345 63346 63347 63348 63349 |
** attached databases that will be use. A mask of these databases
** is maintained in p->btreeMask. The p->lockMask value is the subset of
** p->btreeMask of databases that will require a lock.
*/
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
assert( i>=0 && i<p->db->nDb && i<(int)sizeof(yDbMask)*8 );
assert( i<(int)sizeof(p->btreeMask)*8 );
DbMaskSet(p->btreeMask, i);
if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){
DbMaskSet(p->lockMask, i);
}
}
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
/*
** If SQLite is compiled to support shared-cache mode and to be threadsafe,
** this routine obtains the mutex associated with each BtShared structure
|
| ︙ | ︙ | |||
62983 62984 62985 62986 62987 62988 62989 |
** statement p will ever use. Let N be the number of bits in p->btreeMask
** corresponding to btrees that use shared cache. Then the runtime of
** this routine is N*N. But as N is rarely more than 1, this should not
** be a problem.
*/
SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){
int i;
| < | | | < | | | | 63363 63364 63365 63366 63367 63368 63369 63370 63371 63372 63373 63374 63375 63376 63377 63378 63379 63380 63381 63382 63383 63384 63385 63386 63387 63388 63389 63390 63391 63392 63393 63394 63395 63396 63397 63398 63399 63400 63401 63402 63403 63404 63405 63406 |
** statement p will ever use. Let N be the number of bits in p->btreeMask
** corresponding to btrees that use shared cache. Then the runtime of
** this routine is N*N. But as N is rarely more than 1, this should not
** be a problem.
*/
SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){
int i;
sqlite3 *db;
Db *aDb;
int nDb;
if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
db = p->db;
aDb = db->aDb;
nDb = db->nDb;
for(i=0; i<nDb; i++){
if( i!=1 && DbMaskTest(p->lockMask,i) && ALWAYS(aDb[i].pBt!=0) ){
sqlite3BtreeEnter(aDb[i].pBt);
}
}
}
#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
/*
** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter().
*/
SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){
int i;
sqlite3 *db;
Db *aDb;
int nDb;
if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
db = p->db;
aDb = db->aDb;
nDb = db->nDb;
for(i=0; i<nDb; i++){
if( i!=1 && DbMaskTest(p->lockMask,i) && ALWAYS(aDb[i].pBt!=0) ){
sqlite3BtreeLeave(aDb[i].pBt);
}
}
}
#endif
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
| ︙ | ︙ | |||
63985 63986 63987 63988 63989 63990 63991 |
static void checkActiveVdbeCnt(sqlite3 *db){
Vdbe *p;
int cnt = 0;
int nWrite = 0;
int nRead = 0;
p = db->pVdbe;
while( p ){
| | | 64363 64364 64365 64366 64367 64368 64369 64370 64371 64372 64373 64374 64375 64376 64377 |
static void checkActiveVdbeCnt(sqlite3 *db){
Vdbe *p;
int cnt = 0;
int nWrite = 0;
int nRead = 0;
p = db->pVdbe;
while( p ){
if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){
cnt++;
if( p->readOnly==0 ) nWrite++;
if( p->bIsReader ) nRead++;
}
p = p->pNext;
}
assert( cnt==db->nVdbeActive );
|
| ︙ | ︙ | |||
64145 64146 64147 64148 64149 64150 64151 |
int isSpecialError; /* Set to true if a 'special' error */
/* Lock all btrees used by the statement */
sqlite3VdbeEnter(p);
/* Check for one of the special errors */
mrc = p->rc & 0xff;
| < | 64523 64524 64525 64526 64527 64528 64529 64530 64531 64532 64533 64534 64535 64536 |
int isSpecialError; /* Set to true if a 'special' error */
/* Lock all btrees used by the statement */
sqlite3VdbeEnter(p);
/* Check for one of the special errors */
mrc = p->rc & 0xff;
isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|| mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
if( isSpecialError ){
/* If the query was read-only and the error code is SQLITE_INTERRUPT,
** no rollback is necessary. Otherwise, at least a savepoint
** transaction must be rolled back to restore the database to a
** consistent state.
|
| ︙ | ︙ | |||
64630 64631 64632 64633 64634 64635 64636 |
*/
/*
** Return the serial-type for the value stored in pMem.
*/
SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
int flags = pMem->flags;
| | | 65007 65008 65009 65010 65011 65012 65013 65014 65015 65016 65017 65018 65019 65020 65021 |
*/
/*
** Return the serial-type for the value stored in pMem.
*/
SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
int flags = pMem->flags;
u32 n;
if( flags&MEM_Null ){
return 0;
}
if( flags&MEM_Int ){
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
# define MAX_6BYTE ((((i64)0x00008000)<<32)-1)
|
| ︙ | ︙ | |||
64660 64661 64662 64663 64664 64665 64666 |
if( u<=MAX_6BYTE ) return 5;
return 6;
}
if( flags&MEM_Real ){
return 7;
}
assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) );
| > | < | 65037 65038 65039 65040 65041 65042 65043 65044 65045 65046 65047 65048 65049 65050 65051 65052 65053 65054 65055 |
if( u<=MAX_6BYTE ) return 5;
return 6;
}
if( flags&MEM_Real ){
return 7;
}
assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) );
assert( pMem->n>=0 );
n = (u32)pMem->n;
if( flags & MEM_Zero ){
n += pMem->u.nZero;
}
return ((n*2) + 12 + ((flags&MEM_Str)!=0));
}
/*
** Return the length of the data corresponding to the supplied serial-type.
*/
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
|
| ︙ | ︙ | |||
67182 67183 67184 67185 67186 67187 67188 |
}
/*
** Return true if the prepared statement is in need of being reset.
*/
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt;
| | | 67559 67560 67561 67562 67563 67564 67565 67566 67567 67568 67569 67570 67571 67572 67573 |
}
/*
** Return true if the prepared statement is in need of being reset.
*/
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt;
return v!=0 && v->pc>=0 && v->magic==VDBE_MAGIC_RUN;
}
/*
** Return a pointer to the next prepared statement after pStmt associated
** with database connection pDb. If pStmt is NULL, return the first
** prepared statement for the database connection. Return NULL if there
** are no more.
|
| ︙ | ︙ | |||
67632 67633 67634 67635 67636 67637 67638 67639 67640 67641 67642 67643 67644 67645 |
** feature is used for test suite validation only and does not appear an
** production builds.
**
** M is an integer, 2 or 3, that indices how many different ways the
** branch can go. It is usually 2. "I" is the direction the branch
** goes. 0 means falls through. 1 means branch is taken. 2 means the
** second alternative branch is taken.
*/
#if !defined(SQLITE_VDBE_COVERAGE)
# define VdbeBranchTaken(I,M)
#else
# define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M)
static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){
if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){
| > > > > > > | 68009 68010 68011 68012 68013 68014 68015 68016 68017 68018 68019 68020 68021 68022 68023 68024 68025 68026 68027 68028 |
** feature is used for test suite validation only and does not appear an
** production builds.
**
** M is an integer, 2 or 3, that indices how many different ways the
** branch can go. It is usually 2. "I" is the direction the branch
** goes. 0 means falls through. 1 means branch is taken. 2 means the
** second alternative branch is taken.
**
** iSrcLine is the source code line (from the __LINE__ macro) that
** generated the VDBE instruction. This instrumentation assumes that all
** source code is in a single file (the amalgamation). Special values 1
** and 2 for the iSrcLine parameter mean that this particular branch is
** always taken or never taken, respectively.
*/
#if !defined(SQLITE_VDBE_COVERAGE)
# define VdbeBranchTaken(I,M)
#else
# define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M)
static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){
if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){
|
| ︙ | ︙ | |||
67740 67741 67742 67743 67744 67745 67746 |
/*
** Try to convert a value into a numeric representation if we can
** do so without loss of information. In other words, if the string
** looks like a number, convert it into a number. If it does not
** look like a number, leave it alone.
*/
static void applyNumericAffinity(Mem *pRec){
| < | | | | | | | | | | | | | < > > | 68123 68124 68125 68126 68127 68128 68129 68130 68131 68132 68133 68134 68135 68136 68137 68138 68139 68140 68141 68142 68143 68144 68145 68146 68147 68148 68149 68150 68151 |
/*
** Try to convert a value into a numeric representation if we can
** do so without loss of information. In other words, if the string
** looks like a number, convert it into a number. If it does not
** look like a number, leave it alone.
*/
static void applyNumericAffinity(Mem *pRec){
double rValue;
i64 iValue;
u8 enc = pRec->enc;
if( (pRec->flags&MEM_Str)==0 ) return;
if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
pRec->u.i = iValue;
pRec->flags |= MEM_Int;
}else{
pRec->r = rValue;
pRec->flags |= MEM_Real;
}
}
#define ApplyNumericAffinity(X) \
if(((X)->flags&(MEM_Real|MEM_Int))==0){applyNumericAffinity(X);}
/*
** Processing is determine by the affinity parameter:
**
** SQLITE_AFF_INTEGER:
** SQLITE_AFF_REAL:
** SQLITE_AFF_NUMERIC:
|
| ︙ | ︙ | |||
67791 67792 67793 67794 67795 67796 67797 |
if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
sqlite3VdbeMemStringify(pRec, enc);
}
pRec->flags &= ~(MEM_Real|MEM_Int);
}else if( affinity!=SQLITE_AFF_NONE ){
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|| affinity==SQLITE_AFF_NUMERIC );
| | | 68174 68175 68176 68177 68178 68179 68180 68181 68182 68183 68184 68185 68186 68187 68188 |
if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
sqlite3VdbeMemStringify(pRec, enc);
}
pRec->flags &= ~(MEM_Real|MEM_Int);
}else if( affinity!=SQLITE_AFF_NONE ){
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|| affinity==SQLITE_AFF_NUMERIC );
ApplyNumericAffinity(pRec);
if( pRec->flags & MEM_Real ){
sqlite3VdbeIntegerAffinity(pRec);
}
}
}
/*
|
| ︙ | ︙ | |||
68372 68373 68374 68375 68376 68377 68378 | pc = (int)pIn1->u.i; pIn1->flags = MEM_Undefined; break; } /* Opcode: InitCoroutine P1 P2 P3 * * ** | | | | > > | | > > | > > | > > | > | | 68755 68756 68757 68758 68759 68760 68761 68762 68763 68764 68765 68766 68767 68768 68769 68770 68771 68772 68773 68774 68775 68776 68777 68778 68779 68780 68781 68782 68783 68784 68785 68786 68787 68788 68789 68790 68791 68792 68793 68794 68795 68796 68797 68798 68799 68800 68801 68802 68803 68804 68805 68806 68807 68808 68809 68810 68811 68812 68813 68814 68815 68816 68817 68818 68819 68820 68821 68822 |
pc = (int)pIn1->u.i;
pIn1->flags = MEM_Undefined;
break;
}
/* Opcode: InitCoroutine P1 P2 P3 * *
**
** Set up register P1 so that it will Yield to the coroutine
** located at address P3.
**
** If P2!=0 then the coroutine implementation immediately follows
** this opcode. So jump over the coroutine implementation to
** address P2.
**
** See also: EndCoroutine
*/
case OP_InitCoroutine: { /* jump */
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
assert( pOp->p2>=0 && pOp->p2<p->nOp );
assert( pOp->p3>=0 && pOp->p3<p->nOp );
pOut = &aMem[pOp->p1];
assert( !VdbeMemDynamic(pOut) );
pOut->u.i = pOp->p3 - 1;
pOut->flags = MEM_Int;
if( pOp->p2 ) pc = pOp->p2 - 1;
break;
}
/* Opcode: EndCoroutine P1 * * * *
**
** The instruction at the address in register P1 is a Yield.
** Jump to the P2 parameter of that Yield.
** After the jump, register P1 becomes undefined.
**
** See also: InitCoroutine
*/
case OP_EndCoroutine: { /* in1 */
VdbeOp *pCaller;
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags==MEM_Int );
assert( pIn1->u.i>=0 && pIn1->u.i<p->nOp );
pCaller = &aOp[pIn1->u.i];
assert( pCaller->opcode==OP_Yield );
assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
pc = pCaller->p2 - 1;
pIn1->flags = MEM_Undefined;
break;
}
/* Opcode: Yield P1 P2 * * *
**
** Swap the program counter with the value in register P1. This
** has the effect of yielding to a coroutine.
**
** If the coroutine that is launched by this instruction ends with
** Yield or Return then continue to the next instruction. But if
** the coroutine launched by this instruction ends with
** EndCoroutine, then jump to P2 rather than continuing with the
** next instruction.
**
** See also: InitCoroutine
*/
case OP_Yield: { /* in1, jump */
int pcDest;
pIn1 = &aMem[pOp->p1];
assert( VdbeMemDynamic(pIn1)==0 );
pIn1->flags = MEM_Int;
pcDest = (int)pIn1->u.i;
|
| ︙ | ︙ | |||
68579 68580 68581 68582 68583 68584 68585 | } #endif /* Opcode: String8 * P2 * P4 * ** Synopsis: r[P2]='P4' ** ** P4 points to a nul terminated UTF-8 string. This opcode is transformed | | | 68971 68972 68973 68974 68975 68976 68977 68978 68979 68980 68981 68982 68983 68984 68985 |
}
#endif
/* Opcode: String8 * P2 * P4 *
** Synopsis: r[P2]='P4'
**
** P4 points to a nul terminated UTF-8 string. This opcode is transformed
** into a String before it is executed for the first time. During
** this transformation, the length of string P4 is computed and stored
** as the P1 parameter.
*/
case OP_String8: { /* same as TK_STRING, out2-prerelease */
assert( pOp->p4.z!=0 );
pOp->opcode = OP_String;
pOp->p1 = sqlite3Strlen30(pOp->p4.z);
|
| ︙ | ︙ | |||
69801 69802 69803 69804 69805 69806 69807 |
sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1));
}
break;
}
/* Opcode: Once P1 P2 * * *
**
| | | | | > > > > | | | 70193 70194 70195 70196 70197 70198 70199 70200 70201 70202 70203 70204 70205 70206 70207 70208 70209 70210 70211 70212 70213 70214 70215 70216 70217 70218 70219 70220 70221 70222 70223 70224 70225 70226 70227 70228 70229 70230 70231 70232 70233 70234 70235 70236 70237 |
sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1));
}
break;
}
/* Opcode: Once P1 P2 * * *
**
** Check the "once" flag number P1. If it is set, jump to instruction P2.
** Otherwise, set the flag and fall through to the next instruction.
** In other words, this opcode causes all following opcodes up through P2
** (but not including P2) to run just once and to be skipped on subsequent
** times through the loop.
**
** All "once" flags are initially cleared whenever a prepared statement
** first begins to run.
*/
case OP_Once: { /* jump */
assert( pOp->p1<p->nOnceFlag );
VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2);
if( p->aOnceFlag[pOp->p1] ){
pc = pOp->p2-1;
}else{
p->aOnceFlag[pOp->p1] = 1;
}
break;
}
/* Opcode: If P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is true. The value
** is considered true if it is numeric and non-zero. If the value
** in P1 is NULL then take the jump if and only if P3 is non-zero.
*/
/* Opcode: IfNot P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is False. The value
** is considered false if it has a numeric value of zero. If the value
** in P1 is NULL then take the jump if and only if P3 is non-zero.
*/
case OP_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
int c;
pIn1 = &aMem[pOp->p1];
if( pIn1->flags & MEM_Null ){
c = pOp->p3;
|
| ︙ | ︙ | |||
70639 70640 70641 70642 70643 70644 70645 | Btree *pBt; int iMeta; int iGen; assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); assert( pOp->p1>=0 && pOp->p1<db->nDb ); | | | 71035 71036 71037 71038 71039 71040 71041 71042 71043 71044 71045 71046 71047 71048 71049 |
Btree *pBt;
int iMeta;
int iGen;
assert( p->bIsReader );
assert( p->readOnly==0 || pOp->p2==0 );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){
rc = SQLITE_READONLY;
goto abort_due_to_error;
}
pBt = db->aDb[pOp->p1].pBt;
if( pBt ){
|
| ︙ | ︙ | |||
70734 70735 70736 70737 70738 70739 70740 | assert( p->bIsReader ); iDb = pOp->p1; iCookie = pOp->p3; assert( pOp->p3<SQLITE_N_BTREE_META ); assert( iDb>=0 && iDb<db->nDb ); assert( db->aDb[iDb].pBt!=0 ); | | | | 71130 71131 71132 71133 71134 71135 71136 71137 71138 71139 71140 71141 71142 71143 71144 71145 71146 71147 71148 71149 71150 71151 71152 71153 71154 71155 71156 71157 71158 71159 71160 71161 71162 71163 71164 71165 |
assert( p->bIsReader );
iDb = pOp->p1;
iCookie = pOp->p3;
assert( pOp->p3<SQLITE_N_BTREE_META );
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 );
assert( DbMaskTest(p->btreeMask, iDb) );
sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta);
pOut->u.i = iMeta;
break;
}
/* Opcode: SetCookie P1 P2 P3 * *
**
** Write the content of register P3 (interpreted as an integer)
** into cookie number P2 of database P1. P2==1 is the schema version.
** P2==2 is the database format. P2==3 is the recommended pager cache
** size, and so forth. P1==0 is the main database file and P1==1 is the
** database file used to store temporary tables.
**
** A transaction must be started before executing this opcode.
*/
case OP_SetCookie: { /* in3 */
Db *pDb;
assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
assert( p->readOnly==0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
pIn3 = &aMem[pOp->p3];
sqlite3VdbeMemIntegerify(pIn3);
/* See note about index shifting on OP_ReadCookie */
|
| ︙ | ︙ | |||
70810 70811 70812 70813 70814 70815 70816 | ** ** The P4 value may be either an integer (P4_INT32) or a pointer to ** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo ** structure, then said structure defines the content and collating ** sequence of the index being opened. Otherwise, if P4 is an integer ** value, it is set to the number of columns in the table. ** | | > > > > > > > > > > > > > > | 71206 71207 71208 71209 71210 71211 71212 71213 71214 71215 71216 71217 71218 71219 71220 71221 71222 71223 71224 71225 71226 71227 71228 71229 71230 71231 71232 71233 71234 | ** ** The P4 value may be either an integer (P4_INT32) or a pointer to ** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo ** structure, then said structure defines the content and collating ** sequence of the index being opened. Otherwise, if P4 is an integer ** value, it is set to the number of columns in the table. ** ** See also: OpenWrite, ReopenIdx */ /* Opcode: ReopenIdx P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** ** The ReopenIdx opcode works exactly like ReadOpen except that it first ** checks to see if the cursor on P1 is already open with a root page ** number of P2 and if it is this opcode becomes a no-op. In other words, ** if the cursor is already open, do not reopen it. ** ** The ReopenIdx opcode may only be used with P5==0 and with P4 being ** a P4_KEYINFO object. Furthermore, the P3 value must be the same as ** every other ReopenIdx or OpenRead for the same cursor number. ** ** See the OpenRead opcode documentation for additional information. */ /* Opcode: OpenWrite P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** ** Open a read/write cursor named P1 on the table or index whose root ** page is P2. Or if P5!=0 use the content of register P2 to find the ** root page. |
| ︙ | ︙ | |||
70832 70833 70834 70835 70836 70837 70838 70839 70840 70841 70842 70843 70844 70845 70846 70847 70848 70849 70850 70851 70852 |
**
** This instruction works just like OpenRead except that it opens the cursor
** in read/write mode. For a given table, there can be one or more read-only
** cursors or a single read/write cursor but not both.
**
** See also OpenRead.
*/
case OP_OpenRead:
case OP_OpenWrite: {
int nField;
KeyInfo *pKeyInfo;
int p2;
int iDb;
int wrFlag;
Btree *pX;
VdbeCursor *pCur;
Db *pDb;
assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 );
assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 );
assert( p->bIsReader );
| > > > > > > > > > > > > > | > | | 71242 71243 71244 71245 71246 71247 71248 71249 71250 71251 71252 71253 71254 71255 71256 71257 71258 71259 71260 71261 71262 71263 71264 71265 71266 71267 71268 71269 71270 71271 71272 71273 71274 71275 71276 71277 71278 71279 71280 71281 71282 71283 71284 71285 71286 71287 71288 71289 71290 71291 71292 71293 71294 71295 71296 |
**
** This instruction works just like OpenRead except that it opens the cursor
** in read/write mode. For a given table, there can be one or more read-only
** cursors or a single read/write cursor but not both.
**
** See also OpenRead.
*/
case OP_ReopenIdx: {
VdbeCursor *pCur;
assert( pOp->p5==0 );
assert( pOp->p4type==P4_KEYINFO );
pCur = p->apCsr[pOp->p1];
if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){
assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */
break;
}
/* If the cursor is not currently open or is open on a different
** index, then fall through into OP_OpenRead to force a reopen */
}
case OP_OpenRead:
case OP_OpenWrite: {
int nField;
KeyInfo *pKeyInfo;
int p2;
int iDb;
int wrFlag;
Btree *pX;
VdbeCursor *pCur;
Db *pDb;
assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 );
assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 );
assert( p->bIsReader );
assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
|| p->readOnly==0 );
if( p->expired ){
rc = SQLITE_ABORT;
break;
}
nField = 0;
pKeyInfo = 0;
p2 = pOp->p2;
iDb = pOp->p3;
assert( iDb>=0 && iDb<db->nDb );
assert( DbMaskTest(p->btreeMask, iDb) );
pDb = &db->aDb[iDb];
pX = pDb->pBt;
assert( pX!=0 );
if( pOp->opcode==OP_OpenWrite ){
wrFlag = 1;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( pDb->pSchema->file_format < p->minWriteFileFormat ){
|
| ︙ | ︙ | |||
70903 70904 70905 70906 70907 70908 70909 70910 70911 70912 70913 70914 70915 70916 | assert( pOp->p1>=0 ); assert( nField>=0 ); testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */ pCur = allocateCursor(p, pOp->p1, nField, iDb, 1); if( pCur==0 ) goto no_mem; pCur->nullRow = 1; pCur->isOrdered = 1; rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); pCur->pKeyInfo = pKeyInfo; assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR)); /* Since it performs no memory allocation or IO, the only value that ** sqlite3BtreeCursor() may return is SQLITE_OK. */ | > | 71327 71328 71329 71330 71331 71332 71333 71334 71335 71336 71337 71338 71339 71340 71341 | assert( pOp->p1>=0 ); assert( nField>=0 ); testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */ pCur = allocateCursor(p, pOp->p1, nField, iDb, 1); if( pCur==0 ) goto no_mem; pCur->nullRow = 1; pCur->isOrdered = 1; pCur->pgnoRoot = p2; rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); pCur->pKeyInfo = pKeyInfo; assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR)); /* Since it performs no memory allocation or IO, the only value that ** sqlite3BtreeCursor() may return is SQLITE_OK. */ |
| ︙ | ︙ | |||
71057 71058 71059 71060 71061 71062 71063 |
case OP_Close: {
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]);
p->apCsr[pOp->p1] = 0;
break;
}
| | > > > > | > > > > | > > > > | > > > > | 71482 71483 71484 71485 71486 71487 71488 71489 71490 71491 71492 71493 71494 71495 71496 71497 71498 71499 71500 71501 71502 71503 71504 71505 71506 71507 71508 71509 71510 71511 71512 71513 71514 71515 71516 71517 71518 71519 71520 71521 71522 71523 71524 71525 71526 71527 71528 71529 71530 71531 71532 71533 71534 71535 71536 71537 71538 71539 71540 71541 71542 71543 71544 71545 71546 71547 71548 71549 71550 71551 71552 71553 71554 71555 71556 71557 71558 71559 71560 71561 71562 71563 71564 |
case OP_Close: {
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]);
p->apCsr[pOp->p1] = 0;
break;
}
/* Opcode: SeekGE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the value in register P3 as the key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the smallest entry that
** is greater than or equal to the key value. If there are no records
** greater than or equal to the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end. In other words, the cursor is
** configured to use Next, not Prev.
**
** See also: Found, NotFound, SeekLt, SeekGt, SeekLe
*/
/* Opcode: SeekGT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the smallest entry that
** is greater than the key value. If there are no records greater than
** the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in forward order,
** from the begining toward the end. In other words, the cursor is
** configured to use Next, not Prev.
**
** See also: Found, NotFound, SeekLt, SeekGe, SeekLe
*/
/* Opcode: SeekLT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the largest entry that
** is less than the key value. If there are no records less than
** the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in reverse order,
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLe
*/
/* Opcode: SeekLE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
** use the value in register P3 as a key. If cursor P1 refers
** to an SQL index, then P3 is the first in an array of P4 registers
** that are used as an unpacked index key.
**
** Reposition cursor P1 so that it points to the largest entry that
** is less than or equal to the key value. If there are no records
** less than or equal to the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in reverse order,
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
case OP_SeekLT: /* jump, in3 */
case OP_SeekLE: /* jump, in3 */
case OP_SeekGE: /* jump, in3 */
case OP_SeekGT: { /* jump, in3 */
|
| ︙ | ︙ | |||
71136 71137 71138 71139 71140 71141 71142 71143 71144 71145 71146 71147 |
assert( OP_SeekLE == OP_SeekLT+1 );
assert( OP_SeekGE == OP_SeekLT+2 );
assert( OP_SeekGT == OP_SeekLT+3 );
assert( pC->isOrdered );
assert( pC->pCursor!=0 );
oc = pOp->opcode;
pC->nullRow = 0;
if( pC->isTable ){
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
** the seek, so covert it. */
pIn3 = &aMem[pOp->p3];
| > > > | | 71577 71578 71579 71580 71581 71582 71583 71584 71585 71586 71587 71588 71589 71590 71591 71592 71593 71594 71595 71596 71597 71598 71599 |
assert( OP_SeekLE == OP_SeekLT+1 );
assert( OP_SeekGE == OP_SeekLT+2 );
assert( OP_SeekGT == OP_SeekLT+3 );
assert( pC->isOrdered );
assert( pC->pCursor!=0 );
oc = pOp->opcode;
pC->nullRow = 0;
#ifdef SQLITE_DEBUG
pC->seekOp = pOp->opcode;
#endif
if( pC->isTable ){
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
** the seek, so covert it. */
pIn3 = &aMem[pOp->p3];
ApplyNumericAffinity(pIn3);
iKey = sqlite3VdbeIntValue(pIn3);
pC->rowidIsValid = 0;
/* If the P3 value could not be converted into an integer without
** loss of information, then special processing is required... */
if( (pIn3->flags & MEM_Int)==0 ){
if( (pIn3->flags & MEM_Real)==0 ){
|
| ︙ | ︙ | |||
71290 71291 71292 71293 71294 71295 71296 71297 71298 71299 71300 71301 71302 71303 71304 71305 71306 71307 71308 71309 71310 71311 71312 71313 71314 71315 71316 71317 71318 71319 71320 71321 71322 71323 71324 71325 71326 71327 71328 71329 71330 71331 71332 71333 71334 71335 71336 71337 |
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.
**
** Cursor P1 is on an index btree. If the record identified by P3 and P4
** is a prefix of any entry in P1 then a jump is made to P2 and
** P1 is left pointing at the matching entry.
**
** See also: NotFound, NoConflict, NotExists. SeekGe
*/
/* Opcode: NotFound P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.
**
** Cursor P1 is on an index btree. If the record identified by P3 and P4
** is not the prefix of any entry in P1 then a jump is made to P2. If P1
** does contain an entry whose prefix matches the P3/P4 record then control
** falls through to the next instruction and P1 is left pointing at the
** matching entry.
**
** See also: Found, NotExists, NoConflict
*/
/* Opcode: NoConflict P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.
**
** Cursor P1 is on an index btree. If the record identified by P3 and P4
** contains any NULL value, jump immediately to P2. If all terms of the
** record are not-NULL then a check is done to determine if any row in the
** P1 index btree has a matching key prefix. If there are no matches, jump
** immediately to P2. If there is a match, fall through and leave the P1
** cursor pointing to the matching row.
**
** This opcode is similar to OP_NotFound with the exceptions that the
** branch is always taken if any part of the search key input is NULL.
**
** See also: NotFound, Found, NotExists
*/
case OP_NoConflict: /* jump, in3 */
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
int alreadyExists;
| > > > > > > > > > > > > | 71734 71735 71736 71737 71738 71739 71740 71741 71742 71743 71744 71745 71746 71747 71748 71749 71750 71751 71752 71753 71754 71755 71756 71757 71758 71759 71760 71761 71762 71763 71764 71765 71766 71767 71768 71769 71770 71771 71772 71773 71774 71775 71776 71777 71778 71779 71780 71781 71782 71783 71784 71785 71786 71787 71788 71789 71790 71791 71792 71793 |
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.
**
** Cursor P1 is on an index btree. If the record identified by P3 and P4
** is a prefix of any entry in P1 then a jump is made to P2 and
** P1 is left pointing at the matching entry.
**
** This operation leaves the cursor in a state where it can be
** advanced in the forward direction. The Next instruction will work,
** but not the Prev instruction.
**
** See also: NotFound, NoConflict, NotExists. SeekGe
*/
/* Opcode: NotFound P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.
**
** Cursor P1 is on an index btree. If the record identified by P3 and P4
** is not the prefix of any entry in P1 then a jump is made to P2. If P1
** does contain an entry whose prefix matches the P3/P4 record then control
** falls through to the next instruction and P1 is left pointing at the
** matching entry.
**
** This operation leaves the cursor in a state where it cannot be
** advanced in either direction. In other words, the Next and Prev
** opcodes do not work after this operation.
**
** See also: Found, NotExists, NoConflict
*/
/* Opcode: NoConflict P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.
**
** Cursor P1 is on an index btree. If the record identified by P3 and P4
** contains any NULL value, jump immediately to P2. If all terms of the
** record are not-NULL then a check is done to determine if any row in the
** P1 index btree has a matching key prefix. If there are no matches, jump
** immediately to P2. If there is a match, fall through and leave the P1
** cursor pointing to the matching row.
**
** This opcode is similar to OP_NotFound with the exceptions that the
** branch is always taken if any part of the search key input is NULL.
**
** This operation leaves the cursor in a state where it cannot be
** advanced in either direction. In other words, the Next and Prev
** opcodes do not work after this operation.
**
** See also: NotFound, Found, NotExists
*/
case OP_NoConflict: /* jump, in3 */
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
int alreadyExists;
|
| ︙ | ︙ | |||
71347 71348 71349 71350 71351 71352 71353 71354 71355 71356 71357 71358 71359 71360 |
if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++;
#endif
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p4type==P4_INT32 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
pIn3 = &aMem[pOp->p3];
assert( pC->pCursor!=0 );
assert( pC->isTable==0 );
pFree = 0; /* Not needed. Only used to suppress a compiler warning. */
if( pOp->p4.i>0 ){
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p4.i;
| > > > | 71803 71804 71805 71806 71807 71808 71809 71810 71811 71812 71813 71814 71815 71816 71817 71818 71819 |
if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++;
#endif
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p4type==P4_INT32 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
#ifdef SQLITE_DEBUG
pC->seekOp = pOp->opcode;
#endif
pIn3 = &aMem[pOp->p3];
assert( pC->pCursor!=0 );
assert( pC->isTable==0 );
pFree = 0; /* Not needed. Only used to suppress a compiler warning. */
if( pOp->p4.i>0 ){
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p4.i;
|
| ︙ | ︙ | |||
71417 71418 71419 71420 71421 71422 71423 71424 71425 71426 71427 71428 71429 71430 71431 71432 71433 71434 71435 71436 71437 71438 71439 71440 71441 71442 71443 71444 |
** keys). P3 is an integer rowid. If P1 does not contain a record with
** rowid P3 then jump immediately to P2. If P1 does contain a record
** with rowid P3 then leave the cursor pointing at that record and fall
** through to the next instruction.
**
** The OP_NotFound opcode performs the same operation on index btrees
** (with arbitrary multi-value keys).
**
** See also: Found, NotFound, NoConflict
*/
case OP_NotExists: { /* jump, in3 */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->isTable );
assert( pC->pseudoTableReg==0 );
pCrsr = pC->pCursor;
assert( pCrsr!=0 );
res = 0;
iKey = pIn3->u.i;
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
| > > > > > > > | 71876 71877 71878 71879 71880 71881 71882 71883 71884 71885 71886 71887 71888 71889 71890 71891 71892 71893 71894 71895 71896 71897 71898 71899 71900 71901 71902 71903 71904 71905 71906 71907 71908 71909 71910 |
** keys). P3 is an integer rowid. If P1 does not contain a record with
** rowid P3 then jump immediately to P2. If P1 does contain a record
** with rowid P3 then leave the cursor pointing at that record and fall
** through to the next instruction.
**
** The OP_NotFound opcode performs the same operation on index btrees
** (with arbitrary multi-value keys).
**
** This opcode leaves the cursor in a state where it cannot be advanced
** in either direction. In other words, the Next and Prev opcodes will
** not work following this opcode.
**
** See also: Found, NotFound, NoConflict
*/
case OP_NotExists: { /* jump, in3 */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
#ifdef SQLITE_DEBUG
pC->seekOp = 0;
#endif
assert( pC->isTable );
assert( pC->pseudoTableReg==0 );
pCrsr = pC->pCursor;
assert( pCrsr!=0 );
res = 0;
iKey = pIn3->u.i;
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
|
| ︙ | ︙ | |||
71733 71734 71735 71736 71737 71738 71739 | /* Opcode: Delete P1 P2 * P4 * ** ** Delete the record at which the P1 cursor is currently pointing. ** ** The cursor will be left pointing at either the next or the previous ** record in the table. If it is left pointing at the next record, then ** the next Next instruction will be a no-op. Hence it is OK to delete | | | 72199 72200 72201 72202 72203 72204 72205 72206 72207 72208 72209 72210 72211 72212 72213 | /* Opcode: Delete P1 P2 * P4 * ** ** Delete the record at which the P1 cursor is currently pointing. ** ** The cursor will be left pointing at either the next or the previous ** record in the table. If it is left pointing at the next record, then ** the next Next instruction will be a no-op. Hence it is OK to delete ** a record from within a Next loop. ** ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is ** incremented (otherwise not). ** ** P1 must not be pseudo-table. It has to be a real table with ** multiple rows. ** |
| ︙ | ︙ | |||
71793 71794 71795 71796 71797 71798 71799 |
case OP_ResetCount: {
sqlite3VdbeSetChanges(db, p->nChange);
p->nChange = 0;
break;
}
/* Opcode: SorterCompare P1 P2 P3 P4
| | | | | | | | | 72259 72260 72261 72262 72263 72264 72265 72266 72267 72268 72269 72270 72271 72272 72273 72274 72275 72276 72277 72278 72279 72280 72281 72282 72283 72284 72285 72286 72287 72288 72289 72290 72291 72292 72293 72294 72295 72296 72297 |
case OP_ResetCount: {
sqlite3VdbeSetChanges(db, p->nChange);
p->nChange = 0;
break;
}
/* Opcode: SorterCompare P1 P2 P3 P4
** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2
**
** P1 is a sorter cursor. This instruction compares a prefix of the
** record blob in register P3 against a prefix of the entry that
** the sorter cursor currently points to. Only the first P4 fields
** of r[P3] and the sorter record are compared.
**
** If either P3 or the sorter contains a NULL in one of their significant
** fields (not counting the P4 fields at the end which are ignored) then
** the comparison is assumed to be equal.
**
** Fall through to next instruction if the two records compare equal to
** each other. Jump to P2 if they are different.
*/
case OP_SorterCompare: {
VdbeCursor *pC;
int res;
int nKeyCol;
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
assert( pOp->p4type==P4_INT32 );
pIn3 = &aMem[pOp->p3];
nKeyCol = pOp->p4.i;
rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res);
VdbeBranchTaken(res!=0,2);
if( res ){
pc = pOp->p2-1;
}
break;
};
|
| ︙ | ︙ | |||
71997 71998 71999 72000 72001 72002 72003 |
sqlite3BtreeClearCursor(pC->pCursor);
}
break;
}
/* Opcode: Last P1 P2 * * *
**
| | > > > > > > > | 72463 72464 72465 72466 72467 72468 72469 72470 72471 72472 72473 72474 72475 72476 72477 72478 72479 72480 72481 72482 72483 72484 72485 72486 72487 72488 72489 72490 72491 72492 72493 72494 72495 72496 72497 72498 72499 72500 72501 72502 72503 72504 72505 |
sqlite3BtreeClearCursor(pC->pCursor);
}
break;
}
/* Opcode: Last P1 P2 * * *
**
** The next use of the Rowid or Column or Prev instruction for P1
** will refer to the last entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
**
** This opcode leaves the cursor configured to move in reverse order,
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
*/
case OP_Last: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
pCrsr = pC->pCursor;
res = 0;
assert( pCrsr!=0 );
rc = sqlite3BtreeLast(pCrsr, &res);
pC->nullRow = (u8)res;
pC->deferredMoveto = 0;
pC->rowidIsValid = 0;
pC->cacheStatus = CACHE_STALE;
#ifdef SQLITE_DEBUG
pC->seekOp = OP_Last;
#endif
if( pOp->p2>0 ){
VdbeBranchTaken(res!=0,2);
if( res ) pc = pOp->p2 - 1;
}
break;
}
|
| ︙ | ︙ | |||
72055 72056 72057 72058 72059 72060 72061 72062 72063 72064 72065 72066 72067 72068 72069 72070 72071 72072 72073 72074 72075 72076 72077 72078 72079 |
/* Opcode: Rewind P1 P2 * * *
**
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the first entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Rewind: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
res = 1;
if( isSorter(pC) ){
rc = sqlite3VdbeSorterRewind(db, pC, &res);
}else{
pCrsr = pC->pCursor;
assert( pCrsr );
rc = sqlite3BtreeFirst(pCrsr, &res);
pC->deferredMoveto = 0;
| > > > > > > > | 72528 72529 72530 72531 72532 72533 72534 72535 72536 72537 72538 72539 72540 72541 72542 72543 72544 72545 72546 72547 72548 72549 72550 72551 72552 72553 72554 72555 72556 72557 72558 72559 |
/* Opcode: Rewind P1 P2 * * *
**
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the first entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
**
** This opcode leaves the cursor configured to move in forward order,
** from the begining toward the end. In other words, the cursor is
** configured to use Next, not Prev.
*/
case OP_Rewind: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
res = 1;
#ifdef SQLITE_DEBUG
pC->seekOp = OP_Rewind;
#endif
if( isSorter(pC) ){
rc = sqlite3VdbeSorterRewind(db, pC, &res);
}else{
pCrsr = pC->pCursor;
assert( pCrsr );
rc = sqlite3BtreeFirst(pCrsr, &res);
pC->deferredMoveto = 0;
|
| ︙ | ︙ | |||
72091 72092 72093 72094 72095 72096 72097 72098 72099 72100 72101 72102 72103 72104 72105 72106 72107 72108 72109 72110 72111 72112 72113 72114 72115 72116 | /* Opcode: Next P1 P2 P3 P4 P5 ** ** Advance cursor P1 so that it points to the next key/data pair in its ** table or index. If there are no more key/value pairs then fall through ** to the following instruction. But if the cursor advance was successful, ** jump immediately to P2. ** ** The P1 cursor must be for a real table, not a pseudo-table. P1 must have ** been opened prior to this opcode or the program will segfault. ** ** The P3 value is a hint to the btree implementation. If P3==1, that ** means P1 is an SQL index and that this instruction could have been ** omitted if that index had been unique. P3 is usually 0. P3 is ** always either 0 or 1. ** ** P4 is always of type P4_ADVANCE. The function pointer points to ** sqlite3BtreeNext(). ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. ** ** See also: Prev, NextIfOpen */ /* Opcode: NextIfOpen P1 P2 P3 P4 P5 ** | > > > > | > > > > > | | 72571 72572 72573 72574 72575 72576 72577 72578 72579 72580 72581 72582 72583 72584 72585 72586 72587 72588 72589 72590 72591 72592 72593 72594 72595 72596 72597 72598 72599 72600 72601 72602 72603 72604 72605 72606 72607 72608 72609 72610 72611 72612 72613 72614 72615 72616 72617 72618 72619 72620 72621 72622 72623 72624 72625 72626 72627 72628 72629 72630 72631 72632 72633 72634 72635 72636 72637 72638 72639 |
/* Opcode: Next P1 P2 P3 P4 P5
**
** Advance cursor P1 so that it points to the next key/data pair in its
** table or index. If there are no more key/value pairs then fall through
** to the following instruction. But if the cursor advance was successful,
** jump immediately to P2.
**
** The Next opcode is only valid following an SeekGT, SeekGE, or
** OP_Rewind opcode used to position the cursor. Next is not allowed
** to follow SeekLT, SeekLE, or OP_Last.
**
** The P1 cursor must be for a real table, not a pseudo-table. P1 must have
** been opened prior to this opcode or the program will segfault.
**
** The P3 value is a hint to the btree implementation. If P3==1, that
** means P1 is an SQL index and that this instruction could have been
** omitted if that index had been unique. P3 is usually 0. P3 is
** always either 0 or 1.
**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreeNext().
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
**
** See also: Prev, NextIfOpen
*/
/* Opcode: NextIfOpen P1 P2 P3 P4 P5
**
** This opcode works just like Next except that if cursor P1 is not
** open it behaves a no-op.
*/
/* Opcode: Prev P1 P2 P3 P4 P5
**
** Back up cursor P1 so that it points to the previous key/data pair in its
** table or index. If there is no previous key/value pairs then fall through
** to the following instruction. But if the cursor backup was successful,
** jump immediately to P2.
**
**
** The Prev opcode is only valid following an SeekLT, SeekLE, or
** OP_Last opcode used to position the cursor. Prev is not allowed
** to follow SeekGT, SeekGE, or OP_Rewind.
**
** The P1 cursor must be for a real table, not a pseudo-table. If P1 is
** not open then the behavior is undefined.
**
** The P3 value is a hint to the btree implementation. If P3==1, that
** means P1 is an SQL index and that this instruction could have been
** omitted if that index had been unique. P3 is usually 0. P3 is
** always either 0 or 1.
**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreePrevious().
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
*/
/* Opcode: PrevIfOpen P1 P2 P3 P4 P5
**
** This opcode works just like Prev except that if cursor P1 is not
** open it behaves a no-op.
*/
case OP_SorterNext: { /* jump */
VdbeCursor *pC;
int res;
pC = p->apCsr[pOp->p1];
|
| ︙ | ︙ | |||
72167 72168 72169 72170 72171 72172 72173 72174 72175 72176 72177 72178 72179 72180 |
assert( pC->pCursor );
assert( res==0 || (res==1 && pC->isTable==0) );
testcase( res==1 );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious);
rc = pOp->p4.xAdvance(pC->pCursor, &res);
next_tail:
pC->cacheStatus = CACHE_STALE;
VdbeBranchTaken(res==0,2);
if( res==0 ){
pC->nullRow = 0;
pc = pOp->p2 - 1;
| > > > > > > > > > > | 72656 72657 72658 72659 72660 72661 72662 72663 72664 72665 72666 72667 72668 72669 72670 72671 72672 72673 72674 72675 72676 72677 72678 72679 |
assert( pC->pCursor );
assert( res==0 || (res==1 && pC->isTable==0) );
testcase( res==1 );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious);
/* The Next opcode is only used after SeekGT, SeekGE, and Rewind.
** The Prev opcode is only used after SeekLT, SeekLE, and Last. */
assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen
|| pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE
|| pC->seekOp==OP_Rewind || pC->seekOp==OP_Found);
assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|| pC->seekOp==OP_Last );
rc = pOp->p4.xAdvance(pC->pCursor, &res);
next_tail:
pC->cacheStatus = CACHE_STALE;
VdbeBranchTaken(res==0,2);
if( res==0 ){
pC->nullRow = 0;
pc = pOp->p2 - 1;
|
| ︙ | ︙ | |||
72449 72450 72451 72452 72453 72454 72455 |
pOut->flags = MEM_Null;
if( iCnt>1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
iDb = pOp->p3;
assert( iCnt==1 );
| | | 72948 72949 72950 72951 72952 72953 72954 72955 72956 72957 72958 72959 72960 72961 72962 |
pOut->flags = MEM_Null;
if( iCnt>1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
iDb = pOp->p3;
assert( iCnt==1 );
assert( DbMaskTest(p->btreeMask, iDb) );
iMoved = 0; /* Not needed. Only to silence a warning. */
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
pOut->flags = MEM_Int;
pOut->u.i = iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( rc==SQLITE_OK && iMoved!=0 ){
sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1);
|
| ︙ | ︙ | |||
72489 72490 72491 72492 72493 72494 72495 |
** See also: Destroy
*/
case OP_Clear: {
int nChange;
nChange = 0;
assert( p->readOnly==0 );
| | | 72988 72989 72990 72991 72992 72993 72994 72995 72996 72997 72998 72999 73000 73001 73002 |
** See also: Destroy
*/
case OP_Clear: {
int nChange;
nChange = 0;
assert( p->readOnly==0 );
assert( DbMaskTest(p->btreeMask, pOp->p2) );
rc = sqlite3BtreeClearTable(
db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
);
if( pOp->p3 ){
p->nChange += nChange;
if( pOp->p3>0 ){
assert( memIsValid(&aMem[pOp->p3]) );
|
| ︙ | ︙ | |||
72559 72560 72561 72562 72563 72564 72565 |
case OP_CreateTable: { /* out2-prerelease */
int pgno;
int flags;
Db *pDb;
pgno = 0;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
| | | 73058 73059 73060 73061 73062 73063 73064 73065 73066 73067 73068 73069 73070 73071 73072 |
case OP_CreateTable: { /* out2-prerelease */
int pgno;
int flags;
Db *pDb;
pgno = 0;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
assert( p->readOnly==0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
if( pOp->opcode==OP_CreateTable ){
/* flags = BTREE_INTKEY; */
flags = BTREE_INTKEY;
}else{
|
| ︙ | ︙ | |||
72647 72648 72649 72650 72651 72652 72653 | } #endif /* !defined(SQLITE_OMIT_ANALYZE) */ /* Opcode: DropTable P1 * * P4 * ** ** Remove the internal (in-memory) data structures that describe ** the table named P4 in database P1. This is called after a table | > | > | > | | 73146 73147 73148 73149 73150 73151 73152 73153 73154 73155 73156 73157 73158 73159 73160 73161 73162 73163 73164 73165 73166 73167 73168 73169 73170 73171 73172 73173 73174 73175 73176 73177 73178 73179 73180 73181 73182 73183 73184 73185 73186 73187 |
}
#endif /* !defined(SQLITE_OMIT_ANALYZE) */
/* Opcode: DropTable P1 * * P4 *
**
** Remove the internal (in-memory) data structures that describe
** the table named P4 in database P1. This is called after a table
** is dropped from disk (using the Destroy opcode) in order to keep
** the internal representation of the
** schema consistent with what is on disk.
*/
case OP_DropTable: {
sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z);
break;
}
/* Opcode: DropIndex P1 * * P4 *
**
** Remove the internal (in-memory) data structures that describe
** the index named P4 in database P1. This is called after an index
** is dropped from disk (using the Destroy opcode)
** in order to keep the internal representation of the
** schema consistent with what is on disk.
*/
case OP_DropIndex: {
sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z);
break;
}
/* Opcode: DropTrigger P1 * * P4 *
**
** Remove the internal (in-memory) data structures that describe
** the trigger named P4 in database P1. This is called after a trigger
** is dropped from disk (using the Destroy opcode) in order to keep
** the internal representation of the
** schema consistent with what is on disk.
*/
case OP_DropTrigger: {
sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z);
break;
}
|
| ︙ | ︙ | |||
72724 72725 72726 72727 72728 72729 72730 |
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
pIn1 = &aMem[pOp->p1];
for(j=0; j<nRoot; j++){
aRoot[j] = (int)sqlite3VdbeIntValue(&pIn1[j]);
}
aRoot[j] = 0;
assert( pOp->p5<db->nDb );
| | | 73226 73227 73228 73229 73230 73231 73232 73233 73234 73235 73236 73237 73238 73239 73240 |
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
pIn1 = &aMem[pOp->p1];
for(j=0; j<nRoot; j++){
aRoot[j] = (int)sqlite3VdbeIntValue(&pIn1[j]);
}
aRoot[j] = 0;
assert( pOp->p5<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
(int)pnErr->u.i, &nErr);
sqlite3DbFree(db, aRoot);
pnErr->u.i -= nErr;
sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
assert( z==0 );
|
| ︙ | ︙ | |||
73086 73087 73088 73089 73090 73091 73092 |
VdbeBranchTaken( pIn1->u.i>0, 2);
if( pIn1->u.i>0 ){
pc = pOp->p2 - 1;
}
break;
}
| | | > | < < < > < < < | 73588 73589 73590 73591 73592 73593 73594 73595 73596 73597 73598 73599 73600 73601 73602 73603 73604 73605 73606 73607 73608 73609 73610 73611 73612 73613 73614 73615 73616 73617 73618 73619 73620 73621 73622 73623 |
VdbeBranchTaken( pIn1->u.i>0, 2);
if( pIn1->u.i>0 ){
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: IfNeg P1 P2 P3 * *
** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2
**
** Register P1 must contain an integer. Add literal P3 to the value in
** register P1 then if the value of register P1 is less than zero, jump to P2.
*/
case OP_IfNeg: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
pIn1->u.i += pOp->p3;
VdbeBranchTaken(pIn1->u.i<0, 2);
if( pIn1->u.i<0 ){
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: IfZero P1 P2 P3 * *
** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2
**
** The register P1 must contain an integer. Add literal P3 to the
** value in register P1. If the result is exactly 0, jump to P2.
*/
case OP_IfZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
pIn1->u.i += pOp->p3;
VdbeBranchTaken(pIn1->u.i==0, 2);
if( pIn1->u.i==0 ){
|
| ︙ | ︙ | |||
73384 73385 73386 73387 73388 73389 73390 |
** the P1 database. If the vacuum has finished, jump to instruction
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: { /* jump */
Btree *pBt;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
| | | < | > > | | 73882 73883 73884 73885 73886 73887 73888 73889 73890 73891 73892 73893 73894 73895 73896 73897 73898 73899 73900 73901 73902 73903 73904 73905 73906 73907 73908 73909 73910 73911 73912 73913 73914 73915 73916 73917 |
** the P1 database. If the vacuum has finished, jump to instruction
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: { /* jump */
Btree *pBt;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
assert( p->readOnly==0 );
pBt = db->aDb[pOp->p1].pBt;
rc = sqlite3BtreeIncrVacuum(pBt);
VdbeBranchTaken(rc==SQLITE_DONE,2);
if( rc==SQLITE_DONE ){
pc = pOp->p2 - 1;
rc = SQLITE_OK;
}
break;
}
#endif
/* Opcode: Expire P1 * * * *
**
** Cause precompiled statements to expire. When an expired statement
** is executed using sqlite3_step() it will either automatically
** reprepare itself (if it was originally created using sqlite3_prepare_v2())
** or it will fail with SQLITE_SCHEMA.
**
** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
** then only the currently executing statement is expired.
*/
case OP_Expire: {
if( !pOp->p1 ){
sqlite3ExpirePreparedStatements(db);
}else{
p->expired = 1;
}
|
| ︙ | ︙ | |||
73436 73437 73438 73439 73440 73441 73442 |
** used to generate an error message if the lock cannot be obtained.
*/
case OP_TableLock: {
u8 isWriteLock = (u8)pOp->p3;
if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){
int p1 = pOp->p1;
assert( p1>=0 && p1<db->nDb );
| | | 73935 73936 73937 73938 73939 73940 73941 73942 73943 73944 73945 73946 73947 73948 73949 |
** used to generate an error message if the lock cannot be obtained.
*/
case OP_TableLock: {
u8 isWriteLock = (u8)pOp->p3;
if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){
int p1 = pOp->p1;
assert( p1>=0 && p1<db->nDb );
assert( DbMaskTest(p->btreeMask, p1) );
assert( isWriteLock==0 || isWriteLock==1 );
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
if( (rc&0xFF)==SQLITE_LOCKED ){
const char *z = pOp->p4.z;
sqlite3SetString(&p->zErrMsg, db, "database table is locked: %s", z);
}
}
|
| ︙ | ︙ | |||
73886 73887 73888 73889 73890 73891 73892 |
sqlite3DbFree(db, z);
}
#ifdef SQLITE_USE_FCNTL_TRACE
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
if( zTrace ){
int i;
for(i=0; i<db->nDb; i++){
| | | 74385 74386 74387 74388 74389 74390 74391 74392 74393 74394 74395 74396 74397 74398 74399 |
sqlite3DbFree(db, z);
}
#ifdef SQLITE_USE_FCNTL_TRACE
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
if( zTrace ){
int i;
for(i=0; i<db->nDb; i++){
if( DbMaskTest(p->btreeMask, i)==0 ) continue;
sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace);
}
}
#endif /* SQLITE_USE_FCNTL_TRACE */
#ifdef SQLITE_DEBUG
if( (db->flags & SQLITE_SqlTrace)!=0
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
|
| ︙ | ︙ | |||
74876 74877 74878 74879 74880 74881 74882 | ** be less than key2. Even if key2 also contains NULL values. ** ** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace ** has been allocated and contains an unpacked record that is used as key2. */ static void vdbeSorterCompare( const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */ | | | | < | | 75375 75376 75377 75378 75379 75380 75381 75382 75383 75384 75385 75386 75387 75388 75389 75390 75391 75392 75393 75394 75395 75396 75397 75398 75399 75400 75401 75402 75403 75404 75405 |
** be less than key2. Even if key2 also contains NULL values.
**
** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace
** has been allocated and contains an unpacked record that is used as key2.
*/
static void vdbeSorterCompare(
const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */
int nKeyCol, /* Num of columns. 0 means "all" */
const void *pKey1, int nKey1, /* Left side of comparison */
const void *pKey2, int nKey2, /* Right side of comparison */
int *pRes /* OUT: Result of comparison */
){
KeyInfo *pKeyInfo = pCsr->pKeyInfo;
VdbeSorter *pSorter = pCsr->pSorter;
UnpackedRecord *r2 = pSorter->pUnpacked;
int i;
if( pKey2 ){
sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2);
}
if( nKeyCol ){
r2->nField = nKeyCol;
for(i=0; i<nKeyCol; i++){
if( r2->aMem[i].flags & MEM_Null ){
*pRes = -1;
return;
}
}
assert( r2->default_rc==0 );
}
|
| ︙ | ︙ | |||
75575 75576 75577 75578 75579 75580 75581 | ** Otherwise, set *pRes to a negative, zero or positive value if the ** key in pVal is smaller than, equal to or larger than the current sorter ** key. */ SQLITE_PRIVATE int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ | | | | 76073 76074 76075 76076 76077 76078 76079 76080 76081 76082 76083 76084 76085 76086 76087 76088 76089 76090 76091 76092 76093 76094 |
** Otherwise, set *pRes to a negative, zero or positive value if the
** key in pVal is smaller than, equal to or larger than the current sorter
** key.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
const VdbeCursor *pCsr, /* Sorter cursor */
Mem *pVal, /* Value to compare to current sorter key */
int nKeyCol, /* Only compare this many fields */
int *pRes /* OUT: Result of comparison */
){
VdbeSorter *pSorter = pCsr->pSorter;
void *pKey; int nKey; /* Sorter key to compare pVal with */
pKey = vdbeSorterRowkey(pSorter, &nKey);
vdbeSorterCompare(pCsr, nKeyCol, pVal->z, pVal->n, pKey, nKey, pRes);
return SQLITE_OK;
}
/************** End of vdbesort.c ********************************************/
/************** Begin file journal.c *****************************************/
/*
** 2007 August 22
|
| ︙ | ︙ | |||
76614 76615 76616 76617 76618 76619 76620 |
if( iCol==pTab->iPKey ){
iCol = -1;
}
break;
}
}
if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){
| | | 77112 77113 77114 77115 77116 77117 77118 77119 77120 77121 77122 77123 77124 77125 77126 |
if( iCol==pTab->iPKey ){
iCol = -1;
}
break;
}
}
if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){
/* IMP: R-51414-32910 */
/* IMP: R-44911-55124 */
iCol = -1;
}
if( iCol<pTab->nCol ){
cnt++;
if( iCol<0 ){
pExpr->affinity = SQLITE_AFF_INTEGER;
|
| ︙ | ︙ | |||
76970 76971 76972 76973 76974 76975 76976 |
"constant between 0.0 and 1.0");
pNC->nErr++;
}
}else{
/* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to
** likelihood(X, 0.0625).
** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is short-hand for
| | > > > > | 77468 77469 77470 77471 77472 77473 77474 77475 77476 77477 77478 77479 77480 77481 77482 77483 77484 77485 77486 |
"constant between 0.0 and 1.0");
pNC->nErr++;
}
}else{
/* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is equivalent to
** likelihood(X, 0.0625).
** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is short-hand for
** likelihood(X,0.0625).
** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand for
** likelihood(X,0.9375).
** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to
** likelihood(X,0.9375). */
/* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */
pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938;
}
}
}
#ifndef SQLITE_OMIT_AUTHORIZATION
if( pDef ){
|
| ︙ | ︙ | |||
79083 79084 79085 79086 79087 79088 79089 79090 79091 79092 79093 79094 79095 79096 |
if( op==TK_REGISTER ) op = p->op2;
switch( op ){
case TK_INTEGER:
case TK_STRING:
case TK_FLOAT:
case TK_BLOB:
return 0;
default:
return 1;
}
}
/*
** Return TRUE if the given expression is a constant which would be
| > > > | 79585 79586 79587 79588 79589 79590 79591 79592 79593 79594 79595 79596 79597 79598 79599 79600 79601 |
if( op==TK_REGISTER ) op = p->op2;
switch( op ){
case TK_INTEGER:
case TK_STRING:
case TK_FLOAT:
case TK_BLOB:
return 0;
case TK_COLUMN:
assert( p->pTab!=0 );
return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0;
default:
return 1;
}
}
/*
** Return TRUE if the given expression is a constant which would be
|
| ︙ | ︙ | |||
79190 79191 79192 79193 79194 79195 79196 79197 79198 79199 79200 79201 79202 79203 79204 79205 |
** address of the new instruction.
*/
SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
}
/*
** This function is used by the implementation of the IN (...) operator.
** The pX parameter is the expression on the RHS of the IN operator, which
** might be either a list of expressions or a subquery.
**
** The job of this routine is to find or create a b-tree object that can
** be used either to test for membership in the RHS set or to iterate through
** all members of the RHS set, skipping duplicates.
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > | | | | | > > > > > > > | < > | | | | < < | < < < < | < | < < < | | > | 79695 79696 79697 79698 79699 79700 79701 79702 79703 79704 79705 79706 79707 79708 79709 79710 79711 79712 79713 79714 79715 79716 79717 79718 79719 79720 79721 79722 79723 79724 79725 79726 79727 79728 79729 79730 79731 79732 79733 79734 79735 79736 79737 79738 79739 79740 79741 79742 79743 79744 79745 79746 79747 79748 79749 79750 79751 79752 79753 79754 79755 79756 79757 79758 79759 79760 79761 79762 79763 79764 79765 79766 79767 79768 79769 79770 79771 79772 79773 79774 79775 79776 79777 79778 79779 79780 79781 79782 79783 79784 79785 79786 79787 79788 79789 79790 79791 79792 79793 79794 79795 79796 79797 79798 79799 79800 79801 79802 79803 79804 79805 79806 79807 79808 79809 79810 79811 79812 79813 79814 79815 79816 79817 79818 79819 79820 79821 79822 |
** address of the new instruction.
*/
SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
}
/*
** Generate code that checks the left-most column of index table iCur to see if
** it contains any NULL entries. Cause the register at regHasNull to be set
** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull
** to be set to NULL if iCur contains one or more NULL values.
*/
static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
int j1;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull);
j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull);
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
VdbeComment((v, "first_entry_in(%d)", iCur));
sqlite3VdbeJumpHere(v, j1);
}
#ifndef SQLITE_OMIT_SUBQUERY
/*
** The argument is an IN operator with a list (not a subquery) on the
** right-hand side. Return TRUE if that list is constant.
*/
static int sqlite3InRhsIsConstant(Expr *pIn){
Expr *pLHS;
int res;
assert( !ExprHasProperty(pIn, EP_xIsSelect) );
pLHS = pIn->pLeft;
pIn->pLeft = 0;
res = sqlite3ExprIsConstant(pIn);
pIn->pLeft = pLHS;
return res;
}
#endif
/*
** This function is used by the implementation of the IN (...) operator.
** The pX parameter is the expression on the RHS of the IN operator, which
** might be either a list of expressions or a subquery.
**
** The job of this routine is to find or create a b-tree object that can
** be used either to test for membership in the RHS set or to iterate through
** all members of the RHS set, skipping duplicates.
**
** A cursor is opened on the b-tree object that is the RHS of the IN operator
** and pX->iTable is set to the index of that cursor.
**
** The returned value of this function indicates the b-tree type, as follows:
**
** IN_INDEX_ROWID - The cursor was opened on a database table.
** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
** populated epheremal table.
** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be
** implemented as a sequence of comparisons.
**
** An existing b-tree might be used if the RHS expression pX is a simple
** subquery such as:
**
** SELECT <column> FROM <table>
**
** If the RHS of the IN operator is a list or a more complex subquery, then
** an ephemeral table might need to be generated from the RHS and then
** pX->iTable made to point to the ephermeral table instead of an
** existing table.
**
** The inFlags parameter must contain exactly one of the bits
** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains
** IN_INDEX_MEMBERSHIP, then the generated table will be used for a
** fast membership test. When the IN_INDEX_LOOP bit is set, the
** IN index will be used to loop over all values of the RHS of the
** IN operator.
**
** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate
** through the set members) then the b-tree must not contain duplicates.
** An epheremal table must be used unless the selected <column> is guaranteed
** to be unique - either because it is an INTEGER PRIMARY KEY or it
** has a UNIQUE constraint or UNIQUE index.
**
** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
** for fast set membership tests) then an epheremal table must
** be used unless <column> is an INTEGER PRIMARY KEY or an index can
** be found with <column> as its left-most column.
**
** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and
** if the RHS of the IN operator is a list (not a subquery) then this
** routine might decide that creating an ephemeral b-tree for membership
** testing is too expensive and return IN_INDEX_NOOP. In that case, the
** calling routine should implement the IN operator using a sequence
** of Eq or Ne comparison operations.
**
** When the b-tree is being used for membership tests, the calling function
** might need to know whether or not the RHS side of the IN operator
** contains a NULL. If prRhsHasNull is not a NULL pointer and
** if there is any chance that the (...) might contain a NULL value at
** runtime, then a register is allocated and the register number written
** to *prRhsHasNull. If there is no chance that the (...) contains a
** NULL value, then *prRhsHasNull is left unchanged.
**
** If a register is allocated and its location stored in *prRhsHasNull, then
** the value in that register will be NULL if the b-tree contains one or more
** NULL values, and it will be some non-NULL value if the b-tree contains no
** NULL values.
*/
#ifndef SQLITE_OMIT_SUBQUERY
SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
Select *p; /* SELECT to the right of IN operator */
int eType = 0; /* Type of RHS table. IN_INDEX_* */
int iTab = pParse->nTab++; /* Cursor of the RHS table */
int mustBeUnique; /* True if RHS must be unique */
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
assert( pX->op==TK_IN );
mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
/* Check to see if an existing table or index can be used to
** satisfy the query. This is preferable to generating a new
** ephemeral table.
*/
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
|
| ︙ | ︙ | |||
79319 79320 79321 79322 79323 79324 79325 |
** it is not, it is not possible to use any index.
*/
int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
if( (pIdx->aiColumn[0]==iCol)
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
| | | | | > > > > > > > > > > > > > > > > | | < < < > > | 79865 79866 79867 79868 79869 79870 79871 79872 79873 79874 79875 79876 79877 79878 79879 79880 79881 79882 79883 79884 79885 79886 79887 79888 79889 79890 79891 79892 79893 79894 79895 79896 79897 79898 79899 79900 79901 79902 79903 79904 79905 79906 79907 79908 79909 79910 79911 79912 79913 79914 79915 79916 79917 79918 79919 79920 79921 79922 79923 79924 79925 79926 79927 |
** it is not, it is not possible to use any index.
*/
int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
if( (pIdx->aiColumn[0]==iCol)
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
&& (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx)))
){
int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
*prRhsHasNull = ++pParse->nMem;
sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
}
sqlite3VdbeJumpHere(v, iAddr);
}
}
}
}
/* If no preexisting index is available for the IN clause
** and IN_INDEX_NOOP is an allowed reply
** and the RHS of the IN operator is a list, not a subquery
** and the RHS is not contant or has two or fewer terms,
** then it is not worth creating an ephermeral table to evaluate
** the IN operator so return IN_INDEX_NOOP.
*/
if( eType==0
&& (inFlags & IN_INDEX_NOOP_OK)
&& !ExprHasProperty(pX, EP_xIsSelect)
&& (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
){
eType = IN_INDEX_NOOP;
}
if( eType==0 ){
/* Could not find an existing table or index to use as the RHS b-tree.
** We will have to generate an ephemeral table to do the job.
*/
u32 savedNQueryLoop = pParse->nQueryLoop;
int rMayHaveNull = 0;
eType = IN_INDEX_EPH;
if( inFlags & IN_INDEX_LOOP ){
pParse->nQueryLoop = 0;
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
eType = IN_INDEX_ROWID;
}
}else if( prRhsHasNull ){
*prRhsHasNull = rMayHaveNull = ++pParse->nMem;
}
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
pParse->nQueryLoop = savedNQueryLoop;
}else{
pX->iTable = iTab;
}
return eType;
|
| ︙ | ︙ | |||
79383 79384 79385 79386 79387 79388 79389 | ** to be of the form "<rowid> IN (?, ?, ?)", where <rowid> is a reference ** to some integer key column of a table B-Tree. In this case, use an ** intkey B-Tree to store the set of IN(...) values instead of the usual ** (slower) variable length keys B-Tree. ** ** If rMayHaveNull is non-zero, that means that the operation is an IN ** (not a SELECT or EXISTS) and that the RHS might contains NULLs. | < < | | | < < < < | | | | < < < < | 79944 79945 79946 79947 79948 79949 79950 79951 79952 79953 79954 79955 79956 79957 79958 79959 79960 79961 79962 79963 79964 79965 79966 79967 79968 79969 79970 79971 79972 79973 79974 79975 79976 79977 79978 79979 79980 79981 79982 79983 79984 79985 79986 79987 79988 79989 79990 79991 79992 79993 79994 79995 79996 79997 79998 79999 80000 80001 80002 80003 80004 80005 80006 80007 80008 |
** to be of the form "<rowid> IN (?, ?, ?)", where <rowid> is a reference
** to some integer key column of a table B-Tree. In this case, use an
** intkey B-Tree to store the set of IN(...) values instead of the usual
** (slower) variable length keys B-Tree.
**
** If rMayHaveNull is non-zero, that means that the operation is an IN
** (not a SELECT or EXISTS) and that the RHS might contains NULLs.
** All this routine does is initialize the register given by rMayHaveNull
** to NULL. Calling routines will take care of changing this register
** value to non-NULL if the RHS is NULL-free.
**
** For a SELECT or EXISTS operator, return the register that holds the
** result. For IN operators or if an error occurs, the return value is 0.
*/
#ifndef SQLITE_OMIT_SUBQUERY
SQLITE_PRIVATE int sqlite3CodeSubselect(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The IN, SELECT, or EXISTS operator */
int rHasNullFlag, /* Register that records whether NULLs exist in RHS */
int isRowid /* If true, LHS of IN operator is a rowid */
){
int jmpIfDynamic = -1; /* One-time test address */
int rReg = 0; /* Register storing resulting */
Vdbe *v = sqlite3GetVdbe(pParse);
if( NEVER(v==0) ) return 0;
sqlite3ExprCachePush(pParse);
/* This code must be run in its entirety every time it is encountered
** if any of the following is true:
**
** * The right-hand side is a correlated subquery
** * The right-hand side is an expression list containing variables
** * We are inside a trigger
**
** If all of the above are false, then we can run this code just once
** save the results, and reuse the same result on subsequent invocations.
*/
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v);
}
#ifndef SQLITE_OMIT_EXPLAIN
if( pParse->explain==2 ){
char *zMsg = sqlite3MPrintf(
pParse->db, "EXECUTE %s%s SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ",
pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
);
sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
}
#endif
switch( pExpr->op ){
case TK_IN: {
char affinity; /* Affinity of the LHS of the IN */
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
KeyInfo *pKeyInfo = 0; /* Key information */
affinity = sqlite3ExprAffinity(pLeft);
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
** expression it is handled the same way. An ephemeral table is
** filled with single-field index keys representing the results
** from the SELECT or the <exprlist>.
**
|
| ︙ | ︙ | |||
79469 79470 79471 79472 79473 79474 79475 79476 79477 79478 79479 79480 79481 79482 |
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
**
** Generate code to write the results of the select into the temporary
** table allocated and opened above.
*/
SelectDest dest;
ExprList *pEList;
assert( !isRowid );
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.affSdst = (u8)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
| > | > > | | | 80020 80021 80022 80023 80024 80025 80026 80027 80028 80029 80030 80031 80032 80033 80034 80035 80036 80037 80038 80039 80040 80041 80042 80043 80044 80045 80046 80047 80048 80049 80050 |
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
**
** Generate code to write the results of the select into the temporary
** table allocated and opened above.
*/
Select *pSelect = pExpr->x.pSelect;
SelectDest dest;
ExprList *pEList;
assert( !isRowid );
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.affSdst = (u8)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
pSelect->iLimit = 0;
testcase( pSelect->selFlags & SF_Distinct );
pSelect->selFlags &= ~SF_Distinct;
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
if( sqlite3Select(pParse, pSelect, &dest) ){
sqlite3KeyInfoUnref(pKeyInfo);
return 0;
}
pEList = pSelect->pEList;
assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
assert( pEList!=0 );
assert( pEList->nExpr>0 );
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
pEList->a[0].pExpr);
}else if( ALWAYS(pExpr->x.pList!=0) ){
|
| ︙ | ︙ | |||
79513 79514 79515 79516 79517 79518 79519 |
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
}
/* Loop through each expression in <exprlist>. */
r1 = sqlite3GetTempReg(pParse);
r2 = sqlite3GetTempReg(pParse);
| | | | | | 80067 80068 80069 80070 80071 80072 80073 80074 80075 80076 80077 80078 80079 80080 80081 80082 80083 80084 80085 80086 80087 80088 80089 80090 80091 80092 80093 |
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
}
/* Loop through each expression in <exprlist>. */
r1 = sqlite3GetTempReg(pParse);
r2 = sqlite3GetTempReg(pParse);
if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
Expr *pE2 = pItem->pExpr;
int iValToIns;
/* If the expression is not constant then we will need to
** disable the test that was generated above that makes sure
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){
sqlite3VdbeChangeToNoop(v, jmpIfDynamic);
jmpIfDynamic = -1;
}
/* Evaluate the expression and insert it into the temp table */
if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){
sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns);
}else{
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
|
| ︙ | ︙ | |||
79595 79596 79597 79598 79599 79600 79601 |
}
rReg = dest.iSDParm;
ExprSetVVAProperty(pExpr, EP_NoReduce);
break;
}
}
| > > > | > | | | 80149 80150 80151 80152 80153 80154 80155 80156 80157 80158 80159 80160 80161 80162 80163 80164 80165 80166 80167 80168 80169 80170 80171 80172 80173 80174 80175 80176 80177 80178 80179 80180 80181 80182 80183 80184 80185 80186 80187 80188 80189 |
}
rReg = dest.iSDParm;
ExprSetVVAProperty(pExpr, EP_NoReduce);
break;
}
}
if( rHasNullFlag ){
sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag);
}
if( jmpIfDynamic>=0 ){
sqlite3VdbeJumpHere(v, jmpIfDynamic);
}
sqlite3ExprCachePop(pParse);
return rReg;
}
#endif /* SQLITE_OMIT_SUBQUERY */
#ifndef SQLITE_OMIT_SUBQUERY
/*
** Generate code for an IN expression.
**
** x IN (SELECT ...)
** x IN (value, value, ...)
**
** The left-hand side (LHS) is a scalar expression. The right-hand side (RHS)
** is an array of zero or more values. The expression is true if the LHS is
** contained within the RHS. The value of the expression is unknown (NULL)
** if the LHS is NULL or if the LHS is not contained within the RHS and the
** RHS contains one or more NULL values.
**
** This routine generates code that jumps to destIfFalse if the LHS is not
** contained within the RHS. If due to NULLs we cannot determine if the LHS
** is contained in the RHS then jump to destIfNull. If the LHS is contained
** within the RHS then fall through.
*/
static void sqlite3ExprCodeIN(
Parse *pParse, /* Parsing and code generating context */
Expr *pExpr, /* The IN expression */
|
| ︙ | ︙ | |||
79640 79641 79642 79643 79644 79645 79646 | /* Compute the RHS. After this step, the table with cursor ** pExpr->iTable will contains the values that make up the RHS. */ v = pParse->pVdbe; assert( v!=0 ); /* OOM detected prior to this routine */ VdbeNoopComment((v, "begin IN expr")); | | > > | | > | < < < < < | < | | < | > > > | < < | | < < < < < | < < < < | < < > | | < < < < < > > | > | > > | | < < < | > > | < < < < | < | < < < | < < < < < < | > | > > > > > > > > > > | > > > > | > | > | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | 80198 80199 80200 80201 80202 80203 80204 80205 80206 80207 80208 80209 80210 80211 80212 80213 80214 80215 80216 80217 80218 80219 80220 80221 80222 80223 80224 80225 80226 80227 80228 80229 80230 80231 80232 80233 80234 80235 80236 80237 80238 80239 80240 80241 80242 80243 80244 80245 80246 80247 80248 80249 80250 80251 80252 80253 80254 80255 80256 80257 80258 80259 80260 80261 80262 80263 80264 80265 80266 80267 80268 80269 80270 80271 80272 80273 80274 80275 80276 80277 80278 80279 80280 80281 80282 80283 80284 80285 80286 80287 80288 80289 80290 80291 80292 80293 80294 80295 80296 80297 80298 80299 80300 80301 80302 80303 80304 80305 80306 80307 80308 80309 80310 80311 80312 80313 80314 80315 80316 80317 80318 80319 80320 80321 80322 80323 80324 80325 80326 80327 80328 80329 80330 80331 80332 80333 80334 80335 |
/* Compute the RHS. After this step, the table with cursor
** pExpr->iTable will contains the values that make up the RHS.
*/
v = pParse->pVdbe;
assert( v!=0 ); /* OOM detected prior to this routine */
VdbeNoopComment((v, "begin IN expr"));
eType = sqlite3FindInIndex(pParse, pExpr,
IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
destIfFalse==destIfNull ? 0 : &rRhsHasNull);
/* Figure out the affinity to use to create a key from the results
** of the expression. affinityStr stores a static string suitable for
** P4 of OP_MakeRecord.
*/
affinity = comparisonAffinity(pExpr);
/* Code the LHS, the <expr> from "<expr> IN (...)".
*/
sqlite3ExprCachePush(pParse);
r1 = sqlite3GetTempReg(pParse);
sqlite3ExprCode(pParse, pExpr->pLeft, r1);
/* If sqlite3FindInIndex() did not find or create an index that is
** suitable for evaluating the IN operator, then evaluate using a
** sequence of comparisons.
*/
if( eType==IN_INDEX_NOOP ){
ExprList *pList = pExpr->x.pList;
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
int labelOk = sqlite3VdbeMakeLabel(v);
int r2, regToFree;
int regCkNull = 0;
int ii;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
if( destIfNull!=destIfFalse ){
regCkNull = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull);
}
for(ii=0; ii<pList->nExpr; ii++){
r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree);
if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
}
if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){
sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2,
(void*)pColl, P4_COLLSEQ);
VdbeCoverageIf(v, ii<pList->nExpr-1);
VdbeCoverageIf(v, ii==pList->nExpr-1);
sqlite3VdbeChangeP5(v, affinity);
}else{
assert( destIfNull==destIfFalse );
sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2,
(void*)pColl, P4_COLLSEQ); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL);
}
sqlite3ReleaseTempReg(pParse, regToFree);
}
if( regCkNull ){
sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
}
sqlite3VdbeResolveLabel(v, labelOk);
sqlite3ReleaseTempReg(pParse, regCkNull);
}else{
/* If the LHS is NULL, then the result is either false or NULL depending
** on whether the RHS is empty or not, respectively.
*/
if( sqlite3ExprCanBeNull(pExpr->pLeft) ){
if( destIfNull==destIfFalse ){
/* Shortcut for the common case where the false and NULL outcomes are
** the same. */
sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v);
}else{
int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
sqlite3VdbeJumpHere(v, addr1);
}
}
if( eType==IN_INDEX_ROWID ){
/* In this case, the RHS is the ROWID of table b-tree
*/
sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
VdbeCoverage(v);
}else{
/* In this case, the RHS is an index b-tree.
*/
sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1);
/* If the set membership test fails, then the result of the
** "x IN (...)" expression must be either 0 or NULL. If the set
** contains no NULL values, then the result is 0. If the set
** contains one or more NULL values, then the result of the
** expression is also NULL.
*/
assert( destIfFalse!=destIfNull || rRhsHasNull==0 );
if( rRhsHasNull==0 ){
/* This branch runs if it is known at compile time that the RHS
** cannot contain NULL values. This happens as the result
** of a "NOT NULL" constraint in the database schema.
**
** Also run this branch if NULL is equivalent to FALSE
** for this particular IN operator.
*/
sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
VdbeCoverage(v);
}else{
/* In this branch, the RHS of the IN might contain a NULL and
** the presence of a NULL on the RHS makes a difference in the
** outcome.
*/
int j1;
/* First check to see if the LHS is contained in the RHS. If so,
** then the answer is TRUE the presence of NULLs in the RHS does
** not matter. If the LHS is not contained in the RHS, then the
** answer is NULL if the RHS contains NULLs and the answer is
** FALSE if the RHS is NULL-free.
*/
j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
sqlite3VdbeJumpHere(v, j1);
}
}
}
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ExprCachePop(pParse);
VdbeComment((v, "end IN expr"));
}
#endif /* SQLITE_OMIT_SUBQUERY */
|
| ︙ | ︙ | |||
79790 79791 79792 79793 79794 79795 79796 |
if( negFlag ) i = -i;
sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
}else{
int c;
i64 value;
const char *z = pExpr->u.zToken;
assert( z!=0 );
| | > > > > > > | > | 80382 80383 80384 80385 80386 80387 80388 80389 80390 80391 80392 80393 80394 80395 80396 80397 80398 80399 80400 80401 80402 80403 80404 80405 80406 80407 80408 80409 80410 80411 80412 80413 |
if( negFlag ) i = -i;
sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
}else{
int c;
i64 value;
const char *z = pExpr->u.zToken;
assert( z!=0 );
c = sqlite3DecOrHexToI64(z, &value);
if( c==0 || (c==2 && negFlag) ){
char *zV;
if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
zV = dup8bytes(v, (char*)&value);
sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
}else{
#ifdef SQLITE_OMIT_FLOATING_POINT
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
#ifndef SQLITE_OMIT_HEX_INTEGER
if( sqlite3_strnicmp(z,"0x",2)==0 ){
sqlite3ErrorMsg(pParse, "hex literal too big: %s", z);
}else
#endif
{
codeReal(v, z, negFlag, iMem);
}
#endif
}
}
}
/*
** Clear a cache entry.
|
| ︙ | ︙ | |||
80346 80347 80348 80349 80350 80351 80352 |
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
testcase( regFree1==0 );
addr = sqlite3VdbeAddOp1(v, op, r1);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
| | | 80945 80946 80947 80948 80949 80950 80951 80952 80953 80954 80955 80956 80957 80958 80959 |
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
testcase( regFree1==0 );
addr = sqlite3VdbeAddOp1(v, op, r1);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
sqlite3VdbeAddOp2(v, OP_Integer, 0, target);
sqlite3VdbeJumpHere(v, addr);
break;
}
case TK_AGG_FUNCTION: {
AggInfo *pInfo = pExpr->pAggInfo;
if( pInfo==0 ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
| ︙ | ︙ | |||
80382 80383 80384 80385 80386 80387 80388 |
pFarg = pExpr->x.pList;
}
nFarg = pFarg ? pFarg->nExpr : 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
| | | 80981 80982 80983 80984 80985 80986 80987 80988 80989 80990 80991 80992 80993 80994 80995 |
pFarg = pExpr->x.pList;
}
nFarg = pFarg ? pFarg->nExpr : 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
if( pDef==0 || pDef->xFunc==0 ){
sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
break;
}
/* Attempt a direct implementation of the built-in COALESCE() and
** IFNULL() functions. This avoids unnecessary evalation of
** arguments past the first non-NULL argument.
|
| ︙ | ︙ | |||
83173 83174 83175 83176 83177 83178 83179 | #endif sqlite3DbFree(p->db, p); } /* ** Implementation of the stat_init(N,K,C) SQL function. The three parameters ** are: | | | | > > > > | | | | > | 83772 83773 83774 83775 83776 83777 83778 83779 83780 83781 83782 83783 83784 83785 83786 83787 83788 83789 83790 83791 83792 83793 83794 83795 83796 83797 83798 83799 | #endif sqlite3DbFree(p->db, p); } /* ** Implementation of the stat_init(N,K,C) SQL function. The three parameters ** are: ** N: The number of columns in the index including the rowid/pk (note 1) ** K: The number of columns in the index excluding the rowid/pk. ** C: The number of rows in the index (note 2) ** ** Note 1: In the special case of the covering index that implements a ** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the ** total number of columns in the table. ** ** Note 2: C is only used for STAT3 and STAT4. ** ** For indexes on ordinary rowid tables, N==K+1. But for indexes on ** WITHOUT ROWID tables, N=K+P where P is the number of columns in the ** PRIMARY KEY of the table. The covering index that implements the ** original WITHOUT ROWID table as N==K as a special case. ** ** This routine allocates the Stat4Accum object in heap memory. The return ** value is a pointer to the the Stat4Accum object encoded as a blob (i.e. ** the size of the blob is sizeof(void*) bytes). */ static void statInit( sqlite3_context *context, |
| ︙ | ︙ | |||
83491 83492 83493 83494 83495 83496 83497 | ** Arguments: ** ** P Pointer to the Stat4Accum object created by stat_init() ** C Index of left-most column to differ from previous row ** R Rowid for the current row. Might be a key record for ** WITHOUT ROWID tables. ** | | > > > | 84095 84096 84097 84098 84099 84100 84101 84102 84103 84104 84105 84106 84107 84108 84109 84110 84111 84112 | ** Arguments: ** ** P Pointer to the Stat4Accum object created by stat_init() ** C Index of left-most column to differ from previous row ** R Rowid for the current row. Might be a key record for ** WITHOUT ROWID tables. ** ** This SQL function always returns NULL. It's purpose it to accumulate ** statistical data and/or samples in the Stat4Accum object about the ** index being analyzed. The stat_get() SQL function will later be used to ** extract relevant information for constructing the sqlite_statN tables. ** ** The R parameter is only used for STAT3 and STAT4 */ static void statPush( sqlite3_context *context, int argc, sqlite3_value **argv |
| ︙ | ︙ | |||
83585 83586 83587 83588 83589 83590 83591 | #define STAT_GET_ROWID 1 /* "rowid" column of stat[34] entry */ #define STAT_GET_NEQ 2 /* "neq" column of stat[34] entry */ #define STAT_GET_NLT 3 /* "nlt" column of stat[34] entry */ #define STAT_GET_NDLT 4 /* "ndlt" column of stat[34] entry */ /* ** Implementation of the stat_get(P,J) SQL function. This routine is | | > > > | 84192 84193 84194 84195 84196 84197 84198 84199 84200 84201 84202 84203 84204 84205 84206 84207 84208 84209 | #define STAT_GET_ROWID 1 /* "rowid" column of stat[34] entry */ #define STAT_GET_NEQ 2 /* "neq" column of stat[34] entry */ #define STAT_GET_NLT 3 /* "nlt" column of stat[34] entry */ #define STAT_GET_NDLT 4 /* "ndlt" column of stat[34] entry */ /* ** Implementation of the stat_get(P,J) SQL function. This routine is ** used to query statistical information that has been gathered into ** the Stat4Accum object by prior calls to stat_push(). The P parameter ** is a BLOB which is decoded into a pointer to the Stat4Accum objects. ** The content to returned is determined by the parameter J ** which is one of the STAT_GET_xxxx values defined above. ** ** If neither STAT3 nor STAT4 are enabled, then J is always ** STAT_GET_STAT1 and is hence omitted and this routine becomes ** a one-parameter function, stat_get(P), that always returns the ** stat1 table entry information. */ |
| ︙ | ︙ | |||
83804 83805 83806 83807 83808 83809 83810 |
iTabCur = iTab++;
iIdxCur = iTab++;
pParse->nTab = MAX(pParse->nTab, iTab);
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
| | < < > > > < < | 84414 84415 84416 84417 84418 84419 84420 84421 84422 84423 84424 84425 84426 84427 84428 84429 84430 84431 84432 84433 84434 84435 84436 84437 84438 84439 84440 84441 84442 84443 84444 |
iTabCur = iTab++;
iIdxCur = iTab++;
pParse->nTab = MAX(pParse->nTab, iTab);
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int nCol; /* Number of columns in pIdx. "N" */
int addrRewind; /* Address of "OP_Rewind iIdxCur" */
int addrNextRow; /* Address of "next_row:" */
const char *zIdxName; /* Name of the index */
int nColTest; /* Number of columns to test for changes */
if( pOnlyIdx && pOnlyIdx!=pIdx ) continue;
if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0;
if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIdx) ){
nCol = pIdx->nKeyCol;
zIdxName = pTab->zName;
nColTest = nCol - 1;
}else{
nCol = pIdx->nColumn;
zIdxName = pIdx->zName;
nColTest = pIdx->uniqNotNull ? pIdx->nKeyCol-1 : nCol-1;
}
/* Populate the register containing the index name. */
sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, zIdxName, 0);
VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName));
/*
** Pseudo-code for loop that calls stat_push():
|
| ︙ | ︙ | |||
83850 83851 83852 83853 83854 83855 83856 |
**
** chng_addr_0:
** regPrev(0) = idx(0)
** chng_addr_1:
** regPrev(1) = idx(1)
** ...
**
| | | | > > | > | | 84459 84460 84461 84462 84463 84464 84465 84466 84467 84468 84469 84470 84471 84472 84473 84474 84475 84476 84477 84478 84479 84480 84481 84482 84483 84484 84485 84486 84487 84488 84489 84490 84491 84492 84493 84494 84495 84496 84497 84498 84499 84500 84501 84502 |
**
** chng_addr_0:
** regPrev(0) = idx(0)
** chng_addr_1:
** regPrev(1) = idx(1)
** ...
**
** endDistinctTest:
** regRowid = idx(rowid)
** stat_push(P, regChng, regRowid)
** Next csr
** if !eof(csr) goto next_row;
**
** end_of_scan:
*/
/* Make sure there are enough memory cells allocated to accommodate
** the regPrev array and a trailing rowid (the rowid slot is required
** when building a record to insert into the sample column of
** the sqlite_stat4 table. */
pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
/* Open a read-only cursor on the index being analyzed. */
assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
/* Invoke the stat_init() function. The arguments are:
**
** (1) the number of columns in the index including the rowid
** (or for a WITHOUT ROWID table, the number of PK columns),
** (2) the number of columns in the key without the rowid/pk
** (3) the number of rows in the index,
**
**
** The third argument is only used for STAT3 and STAT4
*/
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
#endif
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4);
|
| ︙ | ︙ | |||
83898 83899 83900 83901 83902 83903 83904 |
** regChng = 0
** goto next_push_0;
**
*/
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
| < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | > | | | | | | | | | | | | | > > | > < | 84510 84511 84512 84513 84514 84515 84516 84517 84518 84519 84520 84521 84522 84523 84524 84525 84526 84527 84528 84529 84530 84531 84532 84533 84534 84535 84536 84537 84538 84539 84540 84541 84542 84543 84544 84545 84546 84547 84548 84549 84550 84551 84552 84553 84554 84555 84556 84557 84558 84559 84560 84561 84562 84563 84564 84565 84566 84567 84568 84569 84570 84571 84572 84573 84574 84575 84576 84577 84578 84579 84580 84581 84582 84583 84584 84585 84586 |
** regChng = 0
** goto next_push_0;
**
*/
addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
addrNextRow = sqlite3VdbeCurrentAddr(v);
if( nColTest>0 ){
int endDistinctTest = sqlite3VdbeMakeLabel(v);
int *aGotoChng; /* Array of jump instruction addresses */
aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest);
if( aGotoChng==0 ) continue;
/*
** next_row:
** regChng = 0
** if( idx(0) != regPrev(0) ) goto chng_addr_0
** regChng = 1
** if( idx(1) != regPrev(1) ) goto chng_addr_1
** ...
** regChng = N
** goto endDistinctTest
*/
sqlite3VdbeAddOp0(v, OP_Goto);
addrNextRow = sqlite3VdbeCurrentAddr(v);
if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){
/* For a single-column UNIQUE index, once we have found a non-NULL
** row, we know that all the rest will be distinct, so skip
** subsequent distinctness tests. */
sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest);
VdbeCoverage(v);
}
for(i=0; i<nColTest; i++){
char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp);
aGotoChng[i] =
sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
VdbeCoverage(v);
}
sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng);
sqlite3VdbeAddOp2(v, OP_Goto, 0, endDistinctTest);
/*
** chng_addr_0:
** regPrev(0) = idx(0)
** chng_addr_1:
** regPrev(1) = idx(1)
** ...
*/
sqlite3VdbeJumpHere(v, addrNextRow-1);
for(i=0; i<nColTest; i++){
sqlite3VdbeJumpHere(v, aGotoChng[i]);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i);
}
sqlite3VdbeResolveLabel(v, endDistinctTest);
sqlite3DbFree(db, aGotoChng);
}
/*
** chng_addr_N:
** regRowid = idx(rowid) // STAT34 only
** stat_push(P, regChng, regRowid) // 3rd parameter STAT34 only
** Next csr
** if !eof(csr) goto next_row;
*/
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
assert( regRowid==(regStat4+2) );
if( HasRowid(pTab) ){
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
int j, k, regKey;
|
| ︙ | ︙ | |||
84021 84022 84023 84024 84025 84026 84027 |
sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
sqlite3VdbeJumpHere(v, addrIsNull);
}
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
/* End of analysis */
sqlite3VdbeJumpHere(v, addrRewind);
| < | 84650 84651 84652 84653 84654 84655 84656 84657 84658 84659 84660 84661 84662 84663 |
sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
sqlite3VdbeJumpHere(v, addrIsNull);
}
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
/* End of analysis */
sqlite3VdbeJumpHere(v, addrRewind);
}
/* Create a single sqlite_stat1 entry containing NULL as the index
** name and the row count as the content.
*/
if( pOnlyIdx==0 && needTableCnt ){
|
| ︙ | ︙ | |||
84122 84123 84124 84125 84126 84127 84128 84129 84130 84131 84132 84133 84134 84135 |
sqlite3 *db = pParse->db;
int iDb;
int i;
char *z, *zDb;
Table *pTab;
Index *pIdx;
Token *pTableName;
/* Read the database schema. If an error occurs, leave an error message
** and code in pParse and return NULL. */
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
return;
}
| > | 84750 84751 84752 84753 84754 84755 84756 84757 84758 84759 84760 84761 84762 84763 84764 |
sqlite3 *db = pParse->db;
int iDb;
int i;
char *z, *zDb;
Table *pTab;
Index *pIdx;
Token *pTableName;
Vdbe *v;
/* Read the database schema. If an error occurs, leave an error message
** and code in pParse and return NULL. */
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
return;
}
|
| ︙ | ︙ | |||
84169 84170 84171 84172 84173 84174 84175 84176 84177 84178 84179 84180 84181 84182 |
}else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){
analyzeTable(pParse, pTab, 0);
}
sqlite3DbFree(db, z);
}
}
}
}
/*
** Used to pass information from the analyzer reader through to the
** callback routine.
*/
typedef struct analysisInfo analysisInfo;
| > > | 84798 84799 84800 84801 84802 84803 84804 84805 84806 84807 84808 84809 84810 84811 84812 84813 |
}else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){
analyzeTable(pParse, pTab, 0);
}
sqlite3DbFree(db, z);
}
}
}
v = sqlite3GetVdbe(pParse);
if( v ) sqlite3VdbeAddOp0(v, OP_Expire);
}
/*
** Used to pass information from the analyzer reader through to the
** callback routine.
*/
typedef struct analysisInfo analysisInfo;
|
| ︙ | ︙ | |||
84227 84228 84229 84230 84231 84232 84233 |
if( *z==' ' ) z++;
}
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
assert( pIndex!=0 );
#else
if( pIndex )
#endif
| < > | < < | > > > > > > > | 84858 84859 84860 84861 84862 84863 84864 84865 84866 84867 84868 84869 84870 84871 84872 84873 84874 84875 84876 84877 84878 84879 84880 84881 84882 84883 84884 |
if( *z==' ' ) z++;
}
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
assert( pIndex!=0 );
#else
if( pIndex )
#endif
while( z[0] ){
if( sqlite3_strglob("unordered*", z)==0 ){
pIndex->bUnordered = 1;
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
}
#ifdef SQLITE_ENABLE_COSTMULT
else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
}
#endif
while( z[0]!=0 && z[0]!=' ' ) z++;
while( z[0]==' ' ) z++;
}
}
/*
** This callback is invoked once for each index when reading the
** sqlite_stat1 table.
**
|
| ︙ | ︙ | |||
84275 84276 84277 84278 84279 84280 84281 84282 84283 84284 84285 84286 84287 84288 84289 84290 84291 84292 84293 |
pIndex = sqlite3PrimaryKeyIndex(pTable);
}else{
pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
}
z = argv[2];
if( pIndex ){
decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex);
if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
}else{
Index fakeIdx;
fakeIdx.szIdxRow = pTable->szTabRow;
decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
pTable->szTabRow = fakeIdx.szIdxRow;
}
return 0;
}
| > > > > | 84911 84912 84913 84914 84915 84916 84917 84918 84919 84920 84921 84922 84923 84924 84925 84926 84927 84928 84929 84930 84931 84932 84933 |
pIndex = sqlite3PrimaryKeyIndex(pTable);
}else{
pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
}
z = argv[2];
if( pIndex ){
pIndex->bUnordered = 0;
decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex);
if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
}else{
Index fakeIdx;
fakeIdx.szIdxRow = pTable->szTabRow;
#ifdef SQLITE_ENABLE_COSTMULT
fakeIdx.pTable = pTable;
#endif
decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
pTable->szTabRow = fakeIdx.szIdxRow;
}
return 0;
}
|
| ︙ | ︙ | |||
85555 85556 85557 85558 85559 85560 85561 85562 85563 85564 85565 85566 85567 85568 |
p->zName, P4_STATIC);
}
}
#else
#define codeTableLocks(x)
#endif
/*
** This routine is called after a single SQL statement has been
** parsed and a VDBE program to execute that statement has been
** prepared. This routine puts the finishing touches on the
** VDBE program and resets the pParse structure for the next
** parse.
**
| > > > > > > > > > > > > > | 86195 86196 86197 86198 86199 86200 86201 86202 86203 86204 86205 86206 86207 86208 86209 86210 86211 86212 86213 86214 86215 86216 86217 86218 86219 86220 86221 |
p->zName, P4_STATIC);
}
}
#else
#define codeTableLocks(x)
#endif
/*
** Return TRUE if the given yDbMask object is empty - if it contains no
** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero()
** macros when SQLITE_MAX_ATTACHED is greater than 30.
*/
#if SQLITE_MAX_ATTACHED>30
SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){
int i;
for(i=0; i<sizeof(yDbMask); i++) if( m[i] ) return 0;
return 1;
}
#endif
/*
** This routine is called after a single SQL statement has been
** parsed and a VDBE program to execute that statement has been
** prepared. This routine puts the finishing touches on the
** VDBE program and resets the pParse structure for the next
** parse.
**
|
| ︙ | ︙ | |||
85591 85592 85593 85594 85595 85596 85597 |
/* The cookie mask contains one bit for each database file open.
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
** set for each database that is used. Generate code to start a
** transaction on each used database and to verify the schema cookie
** on each used database.
*/
| | | > | | | | 86244 86245 86246 86247 86248 86249 86250 86251 86252 86253 86254 86255 86256 86257 86258 86259 86260 86261 86262 86263 86264 86265 86266 86267 86268 86269 86270 |
/* The cookie mask contains one bit for each database file open.
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
** set for each database that is used. Generate code to start a
** transaction on each used database and to verify the schema cookie
** on each used database.
*/
if( db->mallocFailed==0
&& (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
){
int iDb, i;
assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
sqlite3VdbeJumpHere(v, 0);
for(iDb=0; iDb<db->nDb; iDb++){
if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
sqlite3VdbeUsesBtree(v, iDb);
sqlite3VdbeAddOp4Int(v,
OP_Transaction, /* Opcode */
iDb, /* P1 */
DbMaskTest(pParse->writeMask,iDb), /* P2 */
pParse->cookieValue[iDb], /* P3 */
db->aDb[iDb].pSchema->iGeneration /* P4 */
);
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=0; i<pParse->nVtabLock; i++){
|
| ︙ | ︙ | |||
85658 85659 85660 85661 85662 85663 85664 |
}else{
pParse->rc = SQLITE_ERROR;
}
pParse->nTab = 0;
pParse->nMem = 0;
pParse->nSet = 0;
pParse->nVar = 0;
| | | 86312 86313 86314 86315 86316 86317 86318 86319 86320 86321 86322 86323 86324 86325 86326 |
}else{
pParse->rc = SQLITE_ERROR;
}
pParse->nTab = 0;
pParse->nMem = 0;
pParse->nSet = 0;
pParse->nVar = 0;
DbMaskZero(pParse->cookieMask);
}
/*
** Run the parser and code generator recursively in order to generate
** code for the SQL statement given onto the end of the pParse context
** currently under construction. When the parser is run recursively
** this way, the final OP_Halt is not appended and other initialization
|
| ︙ | ︙ | |||
87558 87559 87560 87561 87562 87563 87564 |
assert( pTable->aCol==0 );
pTable->nCol = pSelTab->nCol;
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
sqlite3DeleteTable(db, pSelTab);
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
| | | 88212 88213 88214 88215 88216 88217 88218 88219 88220 88221 88222 88223 88224 88225 88226 |
assert( pTable->aCol==0 );
pTable->nCol = pSelTab->nCol;
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
sqlite3DeleteTable(db, pSelTab);
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
pTable->pSchema->schemaFlags |= DB_UnresetViews;
}else{
pTable->nCol = 0;
nErr++;
}
sqlite3SelectDelete(db, pSel);
} else {
nErr++;
|
| ︙ | ︙ | |||
88135 88136 88137 88138 88139 88140 88141 |
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
(char *)pKey, P4_KEYINFO);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
assert( pKey!=0 || db->mallocFailed || pParse->nErr );
| | | | 88789 88790 88791 88792 88793 88794 88795 88796 88797 88798 88799 88800 88801 88802 88803 88804 88805 88806 88807 88808 |
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
(char *)pKey, P4_KEYINFO);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
assert( pKey!=0 || db->mallocFailed || pParse->nErr );
if( IsUniqueIndex(pIndex) && pKey!=0 ){
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
addr2 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
pIndex->nKeyCol); VdbeCoverage(v);
sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
}else{
addr2 = sqlite3VdbeCurrentAddr(v);
}
sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord);
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
| ︙ | ︙ | |||
88532 88533 88534 88535 88536 88537 88538 |
** If there are different collating sequences or if the columns of
** the constraint occur in different orders, then the constraints are
** considered distinct and both result in separate indices.
*/
Index *pIdx;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int k;
| | | | 89186 89187 89188 89189 89190 89191 89192 89193 89194 89195 89196 89197 89198 89199 89200 89201 89202 |
** If there are different collating sequences or if the columns of
** the constraint occur in different orders, then the constraints are
** considered distinct and both result in separate indices.
*/
Index *pIdx;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int k;
assert( IsUniqueIndex(pIdx) );
assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF );
assert( IsUniqueIndex(pIndex) );
if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue;
for(k=0; k<pIdx->nKeyCol; k++){
const char *z1;
const char *z2;
if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
z1 = pIdx->azColl[k];
|
| ︙ | ︙ | |||
88725 88726 88727 88728 88729 88730 88731 |
** 6 and each subsequent value (if any) is 5. */
memcpy(&a[1], aVal, nCopy*sizeof(LogEst));
for(i=nCopy+1; i<=pIdx->nKeyCol; i++){
a[i] = 23; assert( 23==sqlite3LogEst(5) );
}
assert( 0==sqlite3LogEst(1) );
| | | 89379 89380 89381 89382 89383 89384 89385 89386 89387 89388 89389 89390 89391 89392 89393 |
** 6 and each subsequent value (if any) is 5. */
memcpy(&a[1], aVal, nCopy*sizeof(LogEst));
for(i=nCopy+1; i<=pIdx->nKeyCol; i++){
a[i] = 23; assert( 23==sqlite3LogEst(5) );
}
assert( 0==sqlite3LogEst(1) );
if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0;
}
/*
** This routine will drop an existing named index. This routine
** implements the DROP INDEX statement.
*/
SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
| ︙ | ︙ | |||
89285 89286 89287 89288 89289 89290 89291 |
** for database iDb. The code to actually verify the schema cookie
** will occur at the end of the top-level VDBE and will be generated
** later, by sqlite3FinishCoding().
*/
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3 *db = pToplevel->db;
| < < | | | 89939 89940 89941 89942 89943 89944 89945 89946 89947 89948 89949 89950 89951 89952 89953 89954 89955 89956 89957 89958 89959 |
** for database iDb. The code to actually verify the schema cookie
** will occur at the end of the top-level VDBE and will be generated
** later, by sqlite3FinishCoding().
*/
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3 *db = pToplevel->db;
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
assert( iDb<SQLITE_MAX_ATTACHED+2 );
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
DbMaskSet(pToplevel->cookieMask, iDb);
pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
if( !OMIT_TEMPDB && iDb==1 ){
sqlite3OpenTempDatabase(pToplevel);
}
}
}
|
| ︙ | ︙ | |||
89332 89333 89334 89335 89336 89337 89338 |
** rollback the whole transaction. For operations where all constraints
** can be checked before any changes are made to the database, it is never
** necessary to undo a write and the checkpoint should not be set.
*/
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3CodeVerifySchema(pParse, iDb);
| | | 89984 89985 89986 89987 89988 89989 89990 89991 89992 89993 89994 89995 89996 89997 89998 |
** rollback the whole transaction. For operations where all constraints
** can be checked before any changes are made to the database, it is never
** necessary to undo a write and the checkpoint should not be set.
*/
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3CodeVerifySchema(pParse, iDb);
DbMaskSet(pToplevel->writeMask, iDb);
pToplevel->isMultiWrite |= setStatement;
}
/*
** Indicate that the statement currently under construction might write
** more than one entry (example: deleting one row then inserting another,
** inserting multiple rows in a table, or inserting a row and index entries.)
|
| ︙ | ︙ | |||
90139 90140 90141 90142 90143 90144 90145 |
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
sqlite3DeleteTable(0, pTab);
}
sqlite3HashClear(&temp1);
sqlite3HashClear(&pSchema->fkeyHash);
pSchema->pSeqTab = 0;
| | | | 90791 90792 90793 90794 90795 90796 90797 90798 90799 90800 90801 90802 90803 90804 90805 90806 90807 |
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
sqlite3DeleteTable(0, pTab);
}
sqlite3HashClear(&temp1);
sqlite3HashClear(&pSchema->fkeyHash);
pSchema->pSeqTab = 0;
if( pSchema->schemaFlags & DB_SchemaLoaded ){
pSchema->iGeneration++;
pSchema->schemaFlags &= ~DB_SchemaLoaded;
}
}
/*
** Find and return the schema associated with a BTree. Create
** a new one if necessary.
*/
|
| ︙ | ︙ | |||
91020 91021 91022 91023 91024 91025 91026 | ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | < | < < | 91672 91673 91674 91675 91676 91677 91678 91679 91680 91681 91682 91683 91684 91685 91686 91687 91688 | ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C-language implementions for many of the SQL ** functions of SQLite. (Some function, and in particular the date and ** time functions, are implemented separately.) */ /* #include <stdlib.h> */ /* #include <assert.h> */ /* ** Return the collating function associated with a function. */ |
| ︙ | ︙ | |||
92987 92988 92989 92990 92991 92992 92993 |
assert( nCol>1 );
aiCol = (int *)sqlite3DbMallocRaw(pParse->db, nCol*sizeof(int));
if( !aiCol ) return 1;
*paiCol = aiCol;
}
for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
| | | 93636 93637 93638 93639 93640 93641 93642 93643 93644 93645 93646 93647 93648 93649 93650 |
assert( nCol>1 );
aiCol = (int *)sqlite3DbMallocRaw(pParse->db, nCol*sizeof(int));
if( !aiCol ) return 1;
*paiCol = aiCol;
}
for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){
/* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number
** of columns. If each indexed column corresponds to a foreign key
** column of pFKey, then this index is a winner. */
if( zKey==0 ){
/* If zKey is NULL, then this foreign key is implicitly mapped to
** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be
|
| ︙ | ︙ | |||
96013 96014 96015 96016 96017 96018 96019 |
&& ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
|| (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
){
return 0; /* Default values must be the same for all columns */
}
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
| | | 96662 96663 96664 96665 96666 96667 96668 96669 96670 96671 96672 96673 96674 96675 96676 |
&& ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
|| (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
){
return 0; /* Default values must be the same for all columns */
}
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
if( IsUniqueIndex(pDestIdx) ){
destHasUniqueIdx = 1;
}
for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
}
if( pSrcIdx==0 ){
return 0; /* pDestIdx has no corresponding index in pSrc */
|
| ︙ | ︙ | |||
96243 96244 96245 96246 96247 96248 96249 96250 96251 96252 96253 96254 96255 96256 |
if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
db->mallocFailed = 1;
goto exec_out;
}
}
}
if( xCallback(pArg, nCol, azVals, azCols) ){
rc = SQLITE_ABORT;
sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
sqlite3Error(db, SQLITE_ABORT, 0);
goto exec_out;
}
}
| > > > | 96892 96893 96894 96895 96896 96897 96898 96899 96900 96901 96902 96903 96904 96905 96906 96907 96908 |
if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
db->mallocFailed = 1;
goto exec_out;
}
}
}
if( xCallback(pArg, nCol, azVals, azCols) ){
/* EVIDENCE-OF: R-38229-40159 If the callback function to
** sqlite3_exec() returns non-zero, then sqlite3_exec() will
** return SQLITE_ABORT. */
rc = SQLITE_ABORT;
sqlite3VdbeFinalize((Vdbe *)pStmt);
pStmt = 0;
sqlite3Error(db, SQLITE_ABORT, 0);
goto exec_out;
}
}
|
| ︙ | ︙ | |||
98020 98021 98022 98023 98024 98025 98026 | ** if the omitFull parameter it 1. ** ** Note that the values returned are one less that the values that ** should be passed into sqlite3BtreeSetSafetyLevel(). The is done ** to support legacy SQL code. The safety level used to be boolean ** and older scripts may have used numbers 0 for OFF and 1 for ON. */ | | | 98672 98673 98674 98675 98676 98677 98678 98679 98680 98681 98682 98683 98684 98685 98686 |
** if the omitFull parameter it 1.
**
** Note that the values returned are one less that the values that
** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
** to support legacy SQL code. The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){
/* 123456789 123456789 */
static const char zText[] = "onoffalseyestruefull";
static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2};
int i, n;
if( sqlite3Isdigit(*z) ){
|
| ︙ | ︙ | |||
98042 98043 98044 98045 98046 98047 98048 | } return dflt; } /* ** Interpret the given string as a boolean value. */ | | | 98694 98695 98696 98697 98698 98699 98700 98701 98702 98703 98704 98705 98706 98707 98708 |
}
return dflt;
}
/*
** Interpret the given string as a boolean value.
*/
SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z, u8 dflt){
return getSafetyLevel(z,1,dflt)!=0;
}
/* The sqlite3GetBoolean() function is used by other modules but the
** remainder of this file is specific to PRAGMA processing. So omit
** the rest of the file if PRAGMAs are omitted from the build.
*/
|
| ︙ | ︙ | |||
98588 98589 98590 98591 98592 98593 98594 |
**
** Get or set the size limit on rollback journal files.
*/
case PragTyp_JOURNAL_SIZE_LIMIT: {
Pager *pPager = sqlite3BtreePager(pDb->pBt);
i64 iLimit = -2;
if( zRight ){
| | | 99240 99241 99242 99243 99244 99245 99246 99247 99248 99249 99250 99251 99252 99253 99254 |
**
** Get or set the size limit on rollback journal files.
*/
case PragTyp_JOURNAL_SIZE_LIMIT: {
Pager *pPager = sqlite3BtreePager(pDb->pBt);
i64 iLimit = -2;
if( zRight ){
sqlite3DecOrHexToI64(zRight, &iLimit);
if( iLimit<-1 ) iLimit = -1;
}
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
returnSingleInt(pParse, "journal_size_limit", iLimit);
break;
}
|
| ︙ | ︙ | |||
98716 98717 98718 98719 98720 98721 98722 |
*/
case PragTyp_MMAP_SIZE: {
sqlite3_int64 sz;
#if SQLITE_MAX_MMAP_SIZE>0
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( zRight ){
int ii;
| | | 99368 99369 99370 99371 99372 99373 99374 99375 99376 99377 99378 99379 99380 99381 99382 |
*/
case PragTyp_MMAP_SIZE: {
sqlite3_int64 sz;
#if SQLITE_MAX_MMAP_SIZE>0
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( zRight ){
int ii;
sqlite3DecOrHexToI64(zRight, &sz);
if( sz<0 ) sz = sqlite3GlobalConfig.szMmap;
if( pId2->n==0 ) db->szMmap = sz;
for(ii=db->nDb-1; ii>=0; ii--){
if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz);
}
}
|
| ︙ | ︙ | |||
99084 99085 99086 99087 99088 99089 99090 |
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
| | | 99736 99737 99738 99739 99740 99741 99742 99743 99744 99745 99746 99747 99748 99749 99750 |
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
}
}
break;
case PragTyp_DATABASE_LIST: {
|
| ︙ | ︙ | |||
99334 99335 99336 99337 99338 99339 99340 |
/* Code that appears at the end of the integrity check. If no error
** messages have been generated, output OK. Otherwise output the
** error message
*/
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList endCode[] = {
| < | | | 99986 99987 99988 99989 99990 99991 99992 99993 99994 99995 99996 99997 99998 99999 100000 100001 |
/* Code that appears at the end of the integrity check. If no error
** messages have been generated, output OK. Otherwise output the
** error message
*/
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList endCode[] = {
{ OP_IfNeg, 1, 0, 0}, /* 0 */
{ OP_String8, 0, 3, 0}, /* 1 */
{ OP_ResultRow, 3, 1, 0},
};
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
/* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
** then iDb is set to the index of the database identified by <db>.
|
| ︙ | ︙ | |||
99448 99449 99450 99451 99452 99453 99454 99455 |
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
}
pParse->nMem = MAX(pParse->nMem, 8+j);
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
| > > > > > > > > > > > > > > > > > > > > | > > | | | | > | > > > > > > > > > > > > > > > > | > > > > > > > > > | 100099 100100 100101 100102 100103 100104 100105 100106 100107 100108 100109 100110 100111 100112 100113 100114 100115 100116 100117 100118 100119 100120 100121 100122 100123 100124 100125 100126 100127 100128 100129 100130 100131 100132 100133 100134 100135 100136 100137 100138 100139 100140 100141 100142 100143 100144 100145 100146 100147 100148 100149 100150 100151 100152 100153 100154 100155 100156 100157 100158 100159 100160 100161 100162 100163 100164 100165 100166 100167 100168 100169 100170 100171 100172 100173 100174 100175 100176 100177 100178 100179 100180 100181 100182 |
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
}
pParse->nMem = MAX(pParse->nMem, 8+j);
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
/* Verify that all NOT NULL columns really are NOT NULL */
for(j=0; j<pTab->nCol; j++){
char *zErr;
int jmp2, jmp3;
if( j==pTab->iPKey ) continue;
if( pTab->aCol[j].notNull==0 ) continue;
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pTab->aCol[j].zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
sqlite3VdbeAddOp0(v, OP_Halt);
sqlite3VdbeJumpHere(v, jmp2);
sqlite3VdbeJumpHere(v, jmp3);
}
/* Validate index entries for the current row */
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2, jmp3, jmp4, jmp5;
int ckUniq = sqlite3VdbeMakeLabel(v);
if( pPk==pIdx ) continue;
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
pPrior, r1);
pPrior = pIdx;
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
/* Verify that an index entry exists for the current table row */
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
pIdx->nColumn); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
" missing from index ", P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
jmp5 = sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
pIdx->zName, P4_TRANSIENT);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
sqlite3VdbeAddOp0(v, OP_Halt);
sqlite3VdbeJumpHere(v, jmp2);
/* For UNIQUE indexes, verify that only one entry exists with the
** current key. The entry is unique if (1) any column is NULL
** or (2) the next entry has a different key */
if( IsUniqueIndex(pIdx) ){
int uniqOk = sqlite3VdbeMakeLabel(v);
int jmp6;
int kk;
for(kk=0; kk<pIdx->nKeyCol; kk++){
int iCol = pIdx->aiColumn[kk];
assert( iCol>=0 && iCol<pTab->nCol );
if( pTab->aCol[iCol].notNull ) continue;
sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
VdbeCoverage(v);
}
jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, uniqOk);
sqlite3VdbeJumpHere(v, jmp6);
sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
pIdx->nKeyCol); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
"non-unique entry in index ", P4_STATIC);
sqlite3VdbeAddOp2(v, OP_Goto, 0, jmp5);
sqlite3VdbeResolveLabel(v, uniqOk);
}
sqlite3VdbeJumpHere(v, jmp4);
sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
#ifndef SQLITE_OMIT_BTREECOUNT
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,
"wrong # of entries in index ", P4_STATIC);
|
| ︙ | ︙ | |||
99494 99495 99496 99497 99498 99499 99500 |
sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
}
#endif /* SQLITE_OMIT_BTREECOUNT */
}
}
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
| | | | | 100193 100194 100195 100196 100197 100198 100199 100200 100201 100202 100203 100204 100205 100206 100207 100208 100209 |
sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
}
#endif /* SQLITE_OMIT_BTREECOUNT */
}
}
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
sqlite3VdbeChangeP3(v, addr, -mxErr);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC);
}
break;
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
#ifndef SQLITE_OMIT_UTF16
/*
** PRAGMA encoding
|
| ︙ | ︙ | |||
99759 99760 99761 99762 99763 99764 99765 |
** PRAGMA soft_heap_limit = N
**
** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted,
** use -1.
*/
case PragTyp_SOFT_HEAP_LIMIT: {
sqlite3_int64 N;
| | | 100458 100459 100460 100461 100462 100463 100464 100465 100466 100467 100468 100469 100470 100471 100472 |
** PRAGMA soft_heap_limit = N
**
** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted,
** use -1.
*/
case PragTyp_SOFT_HEAP_LIMIT: {
sqlite3_int64 N;
if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
sqlite3_soft_heap_limit64(N);
}
returnSingleInt(pParse, "soft_heap_limit", sqlite3_soft_heap_limit64(-1));
break;
}
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
| ︙ | ︙ | |||
101282 101283 101284 101285 101286 101287 101288 |
static void codeOffset(
Vdbe *v, /* Generate code into this VM */
int iOffset, /* Register holding the offset counter */
int iContinue /* Jump here to skip the current record */
){
if( iOffset>0 ){
int addr;
| < | | 101981 101982 101983 101984 101985 101986 101987 101988 101989 101990 101991 101992 101993 101994 101995 |
static void codeOffset(
Vdbe *v, /* Generate code into this VM */
int iOffset, /* Register holding the offset counter */
int iContinue /* Jump here to skip the current record */
){
if( iOffset>0 ){
int addr;
addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
VdbeComment((v, "skip OFFSET records"));
sqlite3VdbeJumpHere(v, addr);
}
}
/*
|
| ︙ | ︙ | |||
101448 101449 101450 101451 101452 101453 101454 |
}else{
sqlite3VdbeAddOp3(v, OP_Eq, regResult+i, iContinue, regPrev+i);
VdbeCoverage(v);
}
sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
}
| | | 102146 102147 102148 102149 102150 102151 102152 102153 102154 102155 102156 102157 102158 102159 102160 |
}else{
sqlite3VdbeAddOp3(v, OP_Eq, regResult+i, iContinue, regPrev+i);
VdbeCoverage(v);
}
sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
}
assert( sqlite3VdbeCurrentAddr(v)==iJump || pParse->db->mallocFailed );
sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nResultCol-1);
break;
}
case WHERE_DISTINCT_UNIQUE: {
sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
break;
|
| ︙ | ︙ | |||
107915 107916 107917 107918 107919 107920 107921 |
if( aToOpen[iDataCur-iBaseCur] ){
assert( pPk!=0 );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
VdbeCoverageNeverTaken(v);
}
labelContinue = labelBreak;
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
| | > | 108613 108614 108615 108616 108617 108618 108619 108620 108621 108622 108623 108624 108625 108626 108627 108628 |
if( aToOpen[iDataCur-iBaseCur] ){
assert( pPk!=0 );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
VdbeCoverageNeverTaken(v);
}
labelContinue = labelBreak;
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
VdbeCoverageIf(v, pPk==0);
VdbeCoverageIf(v, pPk!=0);
}else if( pPk ){
labelContinue = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
addrTop = sqlite3VdbeAddOp2(v, OP_RowKey, iEph, regKey);
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
VdbeCoverage(v);
}else{
|
| ︙ | ︙ | |||
109925 109926 109927 109928 109929 109930 109931 109932 109933 109934 109935 109936 109937 109938 |
** at the end is the choosen query plan.
*/
struct WherePath {
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
LogEst nRow; /* Estimated number of rows generated by this path */
LogEst rCost; /* Total cost of this path */
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
};
/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause. Each WHERE
| > | 110624 110625 110626 110627 110628 110629 110630 110631 110632 110633 110634 110635 110636 110637 110638 |
** at the end is the choosen query plan.
*/
struct WherePath {
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
LogEst nRow; /* Estimated number of rows generated by this path */
LogEst rCost; /* Total cost of this path */
LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
};
/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause. Each WHERE
|
| ︙ | ︙ | |||
111655 111656 111657 111658 111659 111660 111661 |
** where X is a constant value. The collation sequences of the
** comparison and select-list expressions must match those of the index.
**
** 3. All of those index columns for which the WHERE clause does not
** contain a "col=X" term are subject to a NOT NULL constraint.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
| | | 112355 112356 112357 112358 112359 112360 112361 112362 112363 112364 112365 112366 112367 112368 112369 |
** where X is a constant value. The collation sequences of the
** comparison and select-list expressions must match those of the index.
**
** 3. All of those index columns for which the WHERE clause does not
** contain a "col=X" term are subject to a NOT NULL constraint.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( !IsUniqueIndex(pIdx) ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
i16 iCol = pIdx->aiColumn[i];
if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){
int iIdxCol = findIndexCol(pParse, pDistinct, iBase, pIdx, i);
if( iIdxCol<0 || pTab->aCol[iCol].notNull==0 ){
break;
}
|
| ︙ | ︙ | |||
112232 112233 112234 112235 112236 112237 112238 |
){
Index *p = pLoop->u.btree.pIndex;
int nEq = pLoop->u.btree.nEq;
sqlite3 *db = pParse->db;
int nLower = -1;
int nUpper = p->nSample+1;
int rc = SQLITE_OK;
| | > | 112932 112933 112934 112935 112936 112937 112938 112939 112940 112941 112942 112943 112944 112945 112946 112947 |
){
Index *p = pLoop->u.btree.pIndex;
int nEq = pLoop->u.btree.nEq;
sqlite3 *db = pParse->db;
int nLower = -1;
int nUpper = p->nSample+1;
int rc = SQLITE_OK;
int iCol = p->aiColumn[nEq];
u8 aff = iCol>=0 ? p->pTable->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
CollSeq *pColl;
sqlite3_value *p1 = 0; /* Value extracted from pLower */
sqlite3_value *p2 = 0; /* Value extracted from pUpper */
sqlite3_value *pVal = 0; /* Value extracted from record */
pColl = sqlite3LocateCollSeq(pParse, p->azColl[nEq]);
|
| ︙ | ︙ | |||
112706 112707 112708 112709 112710 112711 112712 |
){
testcase( iEq==0 );
testcase( bRev );
bRev = !bRev;
}
assert( pX->op==TK_IN );
iReg = iTarget;
| | | 113407 113408 113409 113410 113411 113412 113413 113414 113415 113416 113417 113418 113419 113420 113421 |
){
testcase( iEq==0 );
testcase( bRev );
bRev = !bRev;
}
assert( pX->op==TK_IN );
iReg = iTarget;
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev );
bRev = !bRev;
}
iTab = pX->iTable;
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
VdbeCoverageIf(v, bRev);
|
| ︙ | ︙ | |||
113607 113608 113609 113610 113611 113612 113613 113614 113615 113616 113617 113618 113619 113620 |
int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
int regRowset = 0; /* Register for RowSet object */
int regRowid = 0; /* Register holding rowid */
int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
int iRetInit; /* Address of regReturn init */
int untestedTerms = 0; /* Some terms not completely tested */
int ii; /* Loop counter */
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
Table *pTab = pTabItem->pTab;
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
assert( pTerm->eOperator & WO_OR );
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
| > | 114308 114309 114310 114311 114312 114313 114314 114315 114316 114317 114318 114319 114320 114321 114322 |
int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
int regRowset = 0; /* Register for RowSet object */
int regRowid = 0; /* Register holding rowid */
int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
int iRetInit; /* Address of regReturn init */
int untestedTerms = 0; /* Some terms not completely tested */
int ii; /* Loop counter */
u16 wctrlFlags; /* Flags for sub-WHERE clause */
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
Table *pTab = pTabItem->pTab;
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
assert( pTerm->eOperator & WO_OR );
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
|
| ︙ | ︙ | |||
113702 113703 113704 113705 113706 113707 113708 113709 113710 113711 113712 113713 113714 113715 113716 113717 113718 113719 113720 |
}
}
/* Run a separate WHERE clause for each term of the OR clause. After
** eliminating duplicates from other WHERE clauses, the action for each
** sub-WHERE clause is to to invoke the main loop body as a subroutine.
*/
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
int j1 = 0; /* Address of jump operation */
if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
pAndExpr->pLeft = pOrExpr;
pOrExpr = pAndExpr;
}
/* Loop through table entries that match term pOrTerm. */
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
| > > < | | 114404 114405 114406 114407 114408 114409 114410 114411 114412 114413 114414 114415 114416 114417 114418 114419 114420 114421 114422 114423 114424 114425 114426 114427 114428 114429 114430 114431 114432 |
}
}
/* Run a separate WHERE clause for each term of the OR clause. After
** eliminating duplicates from other WHERE clauses, the action for each
** sub-WHERE clause is to to invoke the main loop body as a subroutine.
*/
wctrlFlags = WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY;
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
int j1 = 0; /* Address of jump operation */
if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
pAndExpr->pLeft = pOrExpr;
pOrExpr = pAndExpr;
}
/* Loop through table entries that match term pOrTerm. */
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
wctrlFlags, iCovCur);
assert( pSubWInfo || pParse->nErr || db->mallocFailed );
if( pSubWInfo ){
WhereLoop *pSubLoop;
explainOneScan(
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
);
/* This is the sub-WHERE clause body. First skip over
|
| ︙ | ︙ | |||
113806 113807 113808 113809 113810 113811 113812 113813 113814 113815 113816 113817 113818 113819 |
assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0
&& (ii==0 || pSubLoop->u.btree.pIndex==pCov)
&& (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex))
){
assert( pSubWInfo->a[0].iIdxCur==iCovCur );
pCov = pSubLoop->u.btree.pIndex;
}else{
pCov = 0;
}
/* Finish the loop through table entries that match term pOrTerm. */
sqlite3WhereEnd(pSubWInfo);
}
| > | 114509 114510 114511 114512 114513 114514 114515 114516 114517 114518 114519 114520 114521 114522 114523 |
assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0
&& (ii==0 || pSubLoop->u.btree.pIndex==pCov)
&& (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex))
){
assert( pSubWInfo->a[0].iIdxCur==iCovCur );
pCov = pSubLoop->u.btree.pIndex;
wctrlFlags |= WHERE_REOPEN_IDX;
}else{
pCov = 0;
}
/* Finish the loop through table entries that match term pOrTerm. */
sqlite3WhereEnd(pSubWInfo);
}
|
| ︙ | ︙ | |||
114412 114413 114414 114415 114416 114417 114418 114419 114420 114421 114422 114423 114424 114425 |
}
if( j<0 ){
pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1);
}
}
}
/*
** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
** index pIndex. Try to match one more.
**
** When this function is called, pBuilder->pNew->nOut contains the
** number of rows expected to be visited by filtering using the nEq
** terms only. If it is modified, this value is restored before this
| > > > > > > > > > > | 115116 115117 115118 115119 115120 115121 115122 115123 115124 115125 115126 115127 115128 115129 115130 115131 115132 115133 115134 115135 115136 115137 115138 115139 |
}
if( j<0 ){
pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1);
}
}
}
/*
** Adjust the cost C by the costMult facter T. This only occurs if
** compiled with -DSQLITE_ENABLE_COSTMULT
*/
#ifdef SQLITE_ENABLE_COSTMULT
# define ApplyCostMultiplier(C,T) C += T
#else
# define ApplyCostMultiplier(C,T)
#endif
/*
** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
** index pIndex. Try to match one more.
**
** When this function is called, pBuilder->pNew->nOut contains the
** number of rows expected to be visited by filtering using the nEq
** terms only. If it is modified, this value is restored before this
|
| ︙ | ︙ | |||
114547 114548 114549 114550 114551 114552 114553 |
}
assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
** changes "x IN (?)" into "x=?". */
}else if( eOp & (WO_EQ) ){
pNew->wsFlags |= WHERE_COLUMN_EQ;
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
| | | 115261 115262 115263 115264 115265 115266 115267 115268 115269 115270 115271 115272 115273 115274 115275 |
}
assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
** changes "x IN (?)" into "x=?". */
}else if( eOp & (WO_EQ) ){
pNew->wsFlags |= WHERE_COLUMN_EQ;
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
if( iCol>=0 && !IsUniqueIndex(pProbe) ){
pNew->wsFlags |= WHERE_UNQ_WANTED;
}else{
pNew->wsFlags |= WHERE_ONEROW;
}
}
}else if( eOp & WO_ISNULL ){
pNew->wsFlags |= WHERE_COLUMN_NULL;
|
| ︙ | ︙ | |||
114608 114609 114610 114611 114612 114613 114614 |
if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){
testcase( eOp & WO_EQ );
testcase( eOp & WO_ISNULL );
rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut);
}else{
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
}
| < | 115322 115323 115324 115325 115326 115327 115328 115329 115330 115331 115332 115333 115334 115335 |
if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){
testcase( eOp & WO_EQ );
testcase( eOp & WO_ISNULL );
rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut);
}else{
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
}
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */
if( nOut ){
pNew->nOut = sqlite3LogEst(nOut);
if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
pNew->nOut -= nIn;
}
|
| ︙ | ︙ | |||
114640 114641 114642 114643 114644 114645 114646 114647 114648 114649 114650 114651 114652 114653 |
** seek only. Then, if this is a non-covering index, add the cost of
** visiting the rows in the main table. */
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
}
nOutUnadjusted = pNew->nOut;
pNew->rRun += nInMul + nIn;
pNew->nOut += nInMul + nIn;
whereLoopOutputAdjust(pBuilder->pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
| > | 115353 115354 115355 115356 115357 115358 115359 115360 115361 115362 115363 115364 115365 115366 115367 |
** seek only. Then, if this is a non-covering index, add the cost of
** visiting the rows in the main table. */
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
}
ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult);
nOutUnadjusted = pNew->nOut;
pNew->rRun += nInMul + nIn;
pNew->nOut += nInMul + nIn;
whereLoopOutputAdjust(pBuilder->pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
|
| ︙ | ︙ | |||
114759 114760 114761 114762 114763 114764 114765 114766 114767 114768 114769 114770 114771 114772 |
**
** cost = nSeek * (log(nRow) + K * nVisit) // covering index
** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index
**
** Normally, nSeek is 1. nSeek values greater than 1 come about if the
** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans.
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
Bitmask mExtra /* Extra prerequesites for using this table */
){
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
| > > > > > > > > | 115473 115474 115475 115476 115477 115478 115479 115480 115481 115482 115483 115484 115485 115486 115487 115488 115489 115490 115491 115492 115493 115494 |
**
** cost = nSeek * (log(nRow) + K * nVisit) // covering index
** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index
**
** Normally, nSeek is 1. nSeek values greater than 1 come about if the
** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans.
**
** The estimated values (nRow, nVisit, nSeek) often contain a large amount
** of uncertainty. For this reason, scoring is designed to pick plans that
** "do the least harm" if the estimates are inaccurate. For example, a
** log(nRow) factor is omitted from a non-covering index scan in order to
** bias the scoring in favor of using an index, since the worst-case
** performance of using an index is far better than the worst-case performance
** of a full table scan.
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
Bitmask mExtra /* Extra prerequesites for using this table */
){
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
|
| ︙ | ︙ | |||
114846 114847 114848 114849 114850 114851 114852 114853 114854 114855 114856 114857 114858 114859 |
pNew->u.btree.pIndex = 0;
pNew->nLTerm = 1;
pNew->aLTerm[0] = pTerm;
/* TUNING: One-time cost for computing the automatic index is
** approximately 7*N*log2(N) where N is the number of rows in
** the table being indexed. */
pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) );
/* TUNING: Each index lookup yields 20 rows in the table. This
** is more than the usual guess of 10 rows, since we have no way
** of knowning how selective the index will ultimately be. It would
** not be unreasonable to make this value much larger. */
pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
pNew->wsFlags = WHERE_AUTO_INDEX;
| > | 115568 115569 115570 115571 115572 115573 115574 115575 115576 115577 115578 115579 115580 115581 115582 |
pNew->u.btree.pIndex = 0;
pNew->nLTerm = 1;
pNew->aLTerm[0] = pTerm;
/* TUNING: One-time cost for computing the automatic index is
** approximately 7*N*log2(N) where N is the number of rows in
** the table being indexed. */
pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) );
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
/* TUNING: Each index lookup yields 20 rows in the table. This
** is more than the usual guess of 10 rows, since we have no way
** of knowning how selective the index will ultimately be. It would
** not be unreasonable to make this value much larger. */
pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
pNew->wsFlags = WHERE_AUTO_INDEX;
|
| ︙ | ︙ | |||
114887 114888 114889 114890 114891 114892 114893 114894 114895 114896 114897 114898 114899 114900 |
/* Integer primary key index */
pNew->wsFlags = WHERE_IPK;
/* Full table scan */
pNew->iSortIdx = b ? iSortIdx : 0;
/* TUNING: Cost of full table scan is (N*3.0). */
pNew->rRun = rSize + 16;
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
}else{
Bitmask m;
if( pProbe->isCovering ){
| > | 115610 115611 115612 115613 115614 115615 115616 115617 115618 115619 115620 115621 115622 115623 115624 |
/* Integer primary key index */
pNew->wsFlags = WHERE_IPK;
/* Full table scan */
pNew->iSortIdx = b ? iSortIdx : 0;
/* TUNING: Cost of full table scan is (N*3.0). */
pNew->rRun = rSize + 16;
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
}else{
Bitmask m;
if( pProbe->isCovering ){
|
| ︙ | ︙ | |||
114922 114923 114924 114925 114926 114927 114928 |
** between 1.1 and 3.0, depending on the relative sizes of the
** index and table rows. If this is a non-covering index scan,
** also add the cost of visiting table rows (N*3.0). */
pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
if( m!=0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
}
| | | 115646 115647 115648 115649 115650 115651 115652 115653 115654 115655 115656 115657 115658 115659 115660 |
** between 1.1 and 3.0, depending on the relative sizes of the
** index and table rows. If this is a non-covering index scan,
** also add the cost of visiting table rows (N*3.0). */
pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
if( m!=0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
}
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
}
}
|
| ︙ | ︙ | |||
115392 115393 115394 115395 115396 115397 115398 |
}else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){
return 0;
}else{
nKeyCol = pIndex->nKeyCol;
nColumn = pIndex->nColumn;
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable));
| | | 116116 116117 116118 116119 116120 116121 116122 116123 116124 116125 116126 116127 116128 116129 116130 |
}else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){
return 0;
}else{
nKeyCol = pIndex->nKeyCol;
nColumn = pIndex->nColumn;
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable));
isOrderDistinct = IsUniqueIndex(pIndex);
}
/* Loop through all columns of the index and deal with the ones
** that are not constrained by == or IN.
*/
rev = revSet = 0;
distinctColumns = 0;
|
| ︙ | ︙ | |||
115560 115561 115562 115563 115564 115565 115566 115567 115568 115569 115570 115571 115572 115573 |
int i;
for(i=0; i<nLoop; i++){ zName[i] = pPath->aLoop[i]->cId; }
if( pLast ) zName[i++] = pLast->cId;
zName[i] = 0;
return zName;
}
#endif
/*
** Given the list of WhereLoop objects at pWInfo->pLoops, this routine
** attempts to find the lowest cost path that visits each WhereLoop
** once. This path is then loaded into the pWInfo->a[].pWLoop fields.
**
** Assume that the total number of output rows that will need to be sorted
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 116284 116285 116286 116287 116288 116289 116290 116291 116292 116293 116294 116295 116296 116297 116298 116299 116300 116301 116302 116303 116304 116305 116306 116307 116308 116309 116310 116311 116312 116313 116314 116315 116316 116317 116318 116319 116320 116321 116322 116323 116324 116325 116326 116327 116328 116329 116330 116331 116332 116333 116334 116335 116336 |
int i;
for(i=0; i<nLoop; i++){ zName[i] = pPath->aLoop[i]->cId; }
if( pLast ) zName[i++] = pLast->cId;
zName[i] = 0;
return zName;
}
#endif
/*
** Return the cost of sorting nRow rows, assuming that the keys have
** nOrderby columns and that the first nSorted columns are already in
** order.
*/
static LogEst whereSortingCost(
WhereInfo *pWInfo,
LogEst nRow,
int nOrderBy,
int nSorted
){
/* TUNING: Estimated cost of a full external sort, where N is
** the number of rows to sort is:
**
** cost = (3.0 * N * log(N)).
**
** Or, if the order-by clause has X terms but only the last Y
** terms are out of order, then block-sorting will reduce the
** sorting cost to:
**
** cost = (3.0 * N * log(N)) * (Y/X)
**
** The (Y/X) term is implemented using stack variable rScale
** below. */
LogEst rScale, rSortCost;
assert( nOrderBy>0 && 66==sqlite3LogEst(100) );
rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
rSortCost = nRow + estLog(nRow) + rScale + 16;
/* TUNING: The cost of implementing DISTINCT using a B-TREE is
** similar but with a larger constant of proportionality.
** Multiply by an additional factor of 3.0. */
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
rSortCost += 16;
}
return rSortCost;
}
/*
** Given the list of WhereLoop objects at pWInfo->pLoops, this routine
** attempts to find the lowest cost path that visits each WhereLoop
** once. This path is then loaded into the pWInfo->a[].pWLoop fields.
**
** Assume that the total number of output rows that will need to be sorted
|
| ︙ | ︙ | |||
115582 115583 115584 115585 115586 115587 115588 | int nLoop; /* Number of terms in the join */ Parse *pParse; /* Parsing context */ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ int mxI = 0; /* Index of next entry to replace */ int nOrderBy; /* Number of ORDER BY clause terms */ | < < > > > | > > > > > > > > > > > | | > | > > > > > > > > > > > > < < < < | | > > > > | > | < > > > > | | | | | > > > | < < < < < < < < < < < < < | < | | > | < < < < | | | | | | > | | < < | | > > > > > > > > > > | > | > > > > > > | > > > > | > | > > > | > > > | 116345 116346 116347 116348 116349 116350 116351 116352 116353 116354 116355 116356 116357 116358 116359 116360 116361 116362 116363 116364 116365 116366 116367 116368 116369 116370 116371 116372 116373 116374 116375 116376 116377 116378 116379 116380 116381 116382 116383 116384 116385 116386 116387 116388 116389 116390 116391 116392 116393 116394 116395 116396 116397 116398 116399 116400 116401 116402 116403 116404 116405 116406 116407 116408 116409 116410 116411 116412 116413 116414 116415 116416 116417 116418 116419 116420 116421 116422 116423 116424 116425 116426 116427 116428 116429 116430 116431 116432 116433 116434 116435 116436 116437 116438 116439 116440 116441 116442 116443 116444 116445 116446 116447 116448 116449 116450 116451 116452 116453 116454 116455 116456 116457 116458 116459 116460 116461 116462 116463 116464 116465 116466 116467 116468 116469 116470 116471 116472 116473 116474 116475 116476 116477 116478 116479 116480 116481 116482 116483 116484 116485 116486 116487 116488 116489 116490 116491 116492 116493 116494 116495 116496 116497 116498 116499 116500 116501 116502 116503 116504 116505 116506 116507 116508 116509 116510 116511 116512 116513 116514 116515 116516 116517 116518 116519 116520 116521 116522 116523 116524 116525 116526 116527 116528 116529 116530 116531 116532 116533 116534 116535 116536 116537 116538 116539 116540 116541 116542 116543 116544 116545 116546 116547 116548 116549 116550 116551 116552 116553 116554 116555 116556 116557 116558 116559 116560 116561 116562 116563 116564 116565 116566 116567 116568 116569 116570 116571 116572 116573 116574 116575 116576 116577 116578 116579 116580 116581 116582 116583 116584 116585 116586 116587 116588 |
int nLoop; /* Number of terms in the join */
Parse *pParse; /* Parsing context */
sqlite3 *db; /* The database connection */
int iLoop; /* Loop counter over the terms of the join */
int ii, jj; /* Loop counters */
int mxI = 0; /* Index of next entry to replace */
int nOrderBy; /* Number of ORDER BY clause terms */
LogEst mxCost = 0; /* Maximum cost of a set of paths */
LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
WherePath *aFrom; /* All nFrom paths at the previous level */
WherePath *aTo; /* The nTo best paths at the current level */
WherePath *pFrom; /* An element of aFrom[] that we are working on */
WherePath *pTo; /* An element of aTo[] that we are working on */
WhereLoop *pWLoop; /* One of the WhereLoop objects */
WhereLoop **pX; /* Used to divy up the pSpace memory */
LogEst *aSortCost = 0; /* Sorting and partial sorting costs */
char *pSpace; /* Temporary memory used by this routine */
int nSpace; /* Bytes of space allocated at pSpace */
pParse = pWInfo->pParse;
db = pParse->db;
nLoop = pWInfo->nLevel;
/* TUNING: For simple queries, only the best path is tracked.
** For 2-way joins, the 5 best paths are followed.
** For joins of 3 or more tables, track the 10 best paths */
mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10);
assert( nLoop<=pWInfo->pTabList->nSrc );
WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst));
/* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this
** case the purpose of this call is to estimate the number of rows returned
** by the overall query. Once this estimate has been obtained, the caller
** will invoke this function a second time, passing the estimate as the
** nRowEst parameter. */
if( pWInfo->pOrderBy==0 || nRowEst==0 ){
nOrderBy = 0;
}else{
nOrderBy = pWInfo->pOrderBy->nExpr;
}
/* Allocate and initialize space for aTo, aFrom and aSortCost[] */
nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
nSpace += sizeof(LogEst) * nOrderBy;
pSpace = sqlite3DbMallocRaw(db, nSpace);
if( pSpace==0 ) return SQLITE_NOMEM;
aTo = (WherePath*)pSpace;
aFrom = aTo+mxChoice;
memset(aFrom, 0, sizeof(aFrom[0]));
pX = (WhereLoop**)(aFrom+mxChoice);
for(ii=mxChoice*2, pFrom=aTo; ii>0; ii--, pFrom++, pX += nLoop){
pFrom->aLoop = pX;
}
if( nOrderBy ){
/* If there is an ORDER BY clause and it is not being ignored, set up
** space for the aSortCost[] array. Each element of the aSortCost array
** is either zero - meaning it has not yet been initialized - or the
** cost of sorting nRowEst rows of data where the first X terms of
** the ORDER BY clause are already in order, where X is the array
** index. */
aSortCost = (LogEst*)pX;
memset(aSortCost, 0, sizeof(LogEst) * nOrderBy);
}
assert( aSortCost==0 || &pSpace[nSpace]==(char*)&aSortCost[nOrderBy] );
assert( aSortCost!=0 || &pSpace[nSpace]==(char*)pX );
/* Seed the search with a single WherePath containing zero WhereLoops.
**
** TUNING: Do not let the number of iterations go above 25. If the cost
** of computing an automatic index is not paid back within the first 25
** rows, then do not use the automatic index. */
aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
nFrom = 1;
assert( aFrom[0].isOrdered==0 );
if( nOrderBy ){
/* If nLoop is zero, then there are no FROM terms in the query. Since
** in this case the query may return a maximum of one row, the results
** are already in the requested order. Set isOrdered to nOrderBy to
** indicate this. Or, if nLoop is greater than zero, set isOrdered to
** -1, indicating that the result set may or may not be ordered,
** depending on the loops added to the current plan. */
aFrom[0].isOrdered = nLoop>0 ? -1 : nOrderBy;
}
/* Compute successively longer WherePaths using the previous generation
** of WherePaths as the basis for the next. Keep track of the mxChoice
** best paths at each generation */
for(iLoop=0; iLoop<nLoop; iLoop++){
nTo = 0;
for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
LogEst rCost; /* Cost of path (pFrom+pWLoop) */
LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */
Bitmask maskNew; /* Mask of src visited by (..) */
Bitmask revMask = 0; /* Mask of rev-order loops for (..) */
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
if( isOrdered<0 ){
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
iLoop, pWLoop, &revMask);
}else{
revMask = pFrom->revLoop;
}
if( isOrdered>=0 && isOrdered<nOrderBy ){
if( aSortCost[isOrdered]==0 ){
aSortCost[isOrdered] = whereSortingCost(
pWInfo, nRowEst, nOrderBy, isOrdered
);
}
rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]);
WHERETRACE(0x002,
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy,
rUnsorted, rCost));
}else{
rCost = rUnsorted;
}
/* Check to see if pWLoop should be added to the set of
** mxChoice best-so-far paths.
**
** First look for an existing path among best-so-far paths
** that covers the same set of loops and has the same isOrdered
** setting as the current path candidate.
**
** The term "((pTo->isOrdered^isOrdered)&0x80)==0" is equivalent
** to (pTo->isOrdered==(-1))==(isOrdered==(-1))" for the range
** of legal values for isOrdered, -1..64.
*/
for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
if( pTo->maskLoop==maskNew
&& ((pTo->isOrdered^isOrdered)&0x80)==0
){
testcase( jj==nTo-1 );
break;
}
}
if( jj>=nTo ){
/* None of the existing best-so-far paths match the candidate. */
if( nTo>=mxChoice
&& (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted))
){
/* The current candidate is no better than any of the mxChoice
** paths currently in the best-so-far buffer. So discard
** this candidate as not viable. */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
continue;
}
/* If we reach this points it means that the new candidate path
** needs to be added to the set of best-so-far paths. */
if( nTo<mxChoice ){
/* Increase the size of the aTo set by one */
jj = nTo++;
}else{
/* New path replaces the prior worst to keep count below mxChoice */
jj = mxI;
}
pTo = &aTo[jj];
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
}else{
/* Control reaches here if best-so-far path pTo=aTo[jj] covers the
** same set of loops and has the sam isOrdered setting as the
** candidate path. Check to see if the candidate should replace
** pTo or if the candidate should be skipped */
if( pTo->rCost<rCost || (pTo->rCost==rCost && pTo->nRow<=nOut) ){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Skip %s cost=%-3d,%3d order=%c",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
/* Discard the candidate path from further consideration */
testcase( pTo->rCost==rCost );
continue;
}
testcase( pTo->rCost==rCost+1 );
/* Control reaches here if the candidate path is better than the
** pTo path. Replace pTo with the candidate. */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Update %s cost=%-3d,%3d order=%c",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
}
/* pWLoop is a winner. Add it to the set of best so far */
pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf;
pTo->revLoop = revMask;
pTo->nRow = nOut;
pTo->rCost = rCost;
pTo->rUnsorted = rUnsorted;
pTo->isOrdered = isOrdered;
memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
pTo->aLoop[iLoop] = pWLoop;
if( nTo>=mxChoice ){
mxI = 0;
mxCost = aTo[0].rCost;
mxUnsorted = aTo[0].nRow;
for(jj=1, pTo=&aTo[1]; jj<mxChoice; jj++, pTo++){
if( pTo->rCost>mxCost
|| (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted)
){
mxCost = pTo->rCost;
mxUnsorted = pTo->rUnsorted;
mxI = jj;
}
}
}
}
}
|
| ︙ | ︙ | |||
115907 115908 115909 115910 115911 115912 115913 |
pLoop->u.btree.nEq = 1;
/* TUNING: Cost of a rowid lookup is 10 */
pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pLoop->aLTermSpace==pLoop->aLTerm );
assert( ArraySize(pLoop->aLTermSpace)==4 );
| | | 116712 116713 116714 116715 116716 116717 116718 116719 116720 116721 116722 116723 116724 116725 116726 |
pLoop->u.btree.nEq = 1;
/* TUNING: Cost of a rowid lookup is 10 */
pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pLoop->aLTermSpace==pLoop->aLTerm );
assert( ArraySize(pLoop->aLTermSpace)==4 );
if( !IsUniqueIndex(pIdx)
|| pIdx->pPartIdxWhere!=0
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
) continue;
for(j=0; j<pIdx->nKeyCol; j++){
pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx);
if( pTerm==0 ) break;
pLoop->aLTerm[j] = pTerm;
|
| ︙ | ︙ | |||
116397 116398 116399 116400 116401 116402 116403 116404 116405 116406 116407 116408 116409 116410 |
iIndexCur++;
pJ = pJ->pNext;
}
op = OP_OpenWrite;
pWInfo->aiCurOnePass[1] = iIndexCur;
}else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
iIndexCur = iIdxCur;
}else{
iIndexCur = pParse->nTab++;
}
pLevel->iIdxCur = iIndexCur;
assert( pIx->pSchema==pTab->pSchema );
assert( iIndexCur>=0 );
if( op ){
| > | 117202 117203 117204 117205 117206 117207 117208 117209 117210 117211 117212 117213 117214 117215 117216 |
iIndexCur++;
pJ = pJ->pNext;
}
op = OP_OpenWrite;
pWInfo->aiCurOnePass[1] = iIndexCur;
}else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
iIndexCur = iIdxCur;
if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx;
}else{
iIndexCur = pParse->nTab++;
}
pLevel->iIdxCur = iIndexCur;
assert( pIx->pSchema==pTab->pSchema );
assert( iIndexCur>=0 );
if( op ){
|
| ︙ | ︙ | |||
120721 120722 120723 120724 120725 120726 120727 120728 120729 120730 120731 120732 120733 120734 |
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
testcase( z[0]=='9' );
*tokenType = TK_INTEGER;
for(i=0; sqlite3Isdigit(z[i]); i++){}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( z[i]=='.' ){
i++;
while( sqlite3Isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
| > > > > > > | 121527 121528 121529 121530 121531 121532 121533 121534 121535 121536 121537 121538 121539 121540 121541 121542 121543 121544 121545 121546 |
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
testcase( z[0]=='9' );
*tokenType = TK_INTEGER;
#ifndef SQLITE_OMIT_HEX_INTEGER
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
for(i=3; sqlite3Isxdigit(z[i]); i++){}
return i;
}
#endif
for(i=0; sqlite3Isdigit(z[i]); i++){}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( z[i]=='.' ){
i++;
while( sqlite3Isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
|
| ︙ | ︙ | |||
122168 122169 122170 122171 122172 122173 122174 122175 122176 122177 122178 122179 122180 122181 |
}
/*
** Close an existing SQLite database
*/
static int sqlite3Close(sqlite3 *db, int forceZombie){
if( !db ){
return SQLITE_OK;
}
if( !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
| > > | 122980 122981 122982 122983 122984 122985 122986 122987 122988 122989 122990 122991 122992 122993 122994 122995 |
}
/*
** Close an existing SQLite database
*/
static int sqlite3Close(sqlite3 *db, int forceZombie){
if( !db ){
/* EVIDENCE-OF: R-63257-11740 Calling sqlite3_close() or
** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */
return SQLITE_OK;
}
if( !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
|
| ︙ | ︙ | |||
122397 122398 122399 122400 122401 122402 122403 | } } /* ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ | | | 123211 123212 123213 123214 123215 123216 123217 123218 123219 123220 123221 123222 123223 123224 123225 |
}
}
/*
** Return a static string containing the name corresponding to the error code
** specified in the argument.
*/
#if (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) || defined(SQLITE_TEST)
SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
const char *zName = 0;
int i, origRc = rc;
for(i=0; i<2 && zName==0; i++, rc &= 0xff){
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
|
| ︙ | ︙ | |||
122432 122433 122434 122435 122436 122437 122438 |
case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break;
case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break;
case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break;
case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break;
case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break;
case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break;
case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break;
| < | 123246 123247 123248 123249 123250 123251 123252 123253 123254 123255 123256 123257 123258 123259 |
case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break;
case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break;
case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break;
case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break;
case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break;
case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break;
case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break;
case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break;
case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break;
case SQLITE_IOERR_CHECKRESERVEDLOCK:
zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break;
case SQLITE_IOERR_CLOSE: zName = "SQLITE_IOERR_CLOSE"; break;
case SQLITE_IOERR_DIR_CLOSE: zName = "SQLITE_IOERR_DIR_CLOSE"; break;
|
| ︙ | ︙ | |||
123417 123418 123419 123420 123421 123422 123423 | SQLITE_MAX_COLUMN, SQLITE_MAX_EXPR_DEPTH, SQLITE_MAX_COMPOUND_SELECT, SQLITE_MAX_VDBE_OP, SQLITE_MAX_FUNCTION_ARG, SQLITE_MAX_ATTACHED, SQLITE_MAX_LIKE_PATTERN_LENGTH, | | | 124230 124231 124232 124233 124234 124235 124236 124237 124238 124239 124240 124241 124242 124243 124244 | SQLITE_MAX_COLUMN, SQLITE_MAX_EXPR_DEPTH, SQLITE_MAX_COMPOUND_SELECT, SQLITE_MAX_VDBE_OP, SQLITE_MAX_FUNCTION_ARG, SQLITE_MAX_ATTACHED, SQLITE_MAX_LIKE_PATTERN_LENGTH, SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ SQLITE_MAX_TRIGGER_DEPTH, }; /* ** Make sure the hard limits are set to reasonable values */ #if SQLITE_MAX_LENGTH<100 |
| ︙ | ︙ | |||
123442 123443 123444 123445 123446 123447 123448 | #endif #if SQLITE_MAX_VDBE_OP<40 # error SQLITE_MAX_VDBE_OP must be at least 40 #endif #if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000 # error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000 #endif | | | | 124255 124256 124257 124258 124259 124260 124261 124262 124263 124264 124265 124266 124267 124268 124269 124270 | #endif #if SQLITE_MAX_VDBE_OP<40 # error SQLITE_MAX_VDBE_OP must be at least 40 #endif #if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000 # error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000 #endif #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125 # error SQLITE_MAX_ATTACHED must be between 0 and 125 #endif #if SQLITE_MAX_LIKE_PATTERN_LENGTH<1 # error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1 #endif #if SQLITE_MAX_COLUMN>32767 # error SQLITE_MAX_COLUMN must not exceed 32767 #endif |
| ︙ | ︙ | |||
124702 124703 124704 124705 124706 124707 124708 124709 124710 124711 124712 124713 124714 124715 |
typedef void (*branch_callback)(void*,int,u8,u8);
sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback);
sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*);
#endif
break;
}
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
return rc;
}
/*
| > > > > > > > > > > | 125515 125516 125517 125518 125519 125520 125521 125522 125523 125524 125525 125526 125527 125528 125529 125530 125531 125532 125533 125534 125535 125536 125537 125538 |
typedef void (*branch_callback)(void*,int,u8,u8);
sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback);
sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*);
#endif
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT);
**
** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if
** not.
*/
case SQLITE_TESTCTRL_ISINIT: {
if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR;
break;
}
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
return rc;
}
/*
|
| ︙ | ︙ | |||
124750 124751 124752 124753 124754 124755 124756 |
SQLITE_API sqlite3_int64 sqlite3_uri_int64(
const char *zFilename, /* Filename as passed to xOpen */
const char *zParam, /* URI parameter sought */
sqlite3_int64 bDflt /* return if parameter is missing */
){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
sqlite3_int64 v;
| | | 125573 125574 125575 125576 125577 125578 125579 125580 125581 125582 125583 125584 125585 125586 125587 |
SQLITE_API sqlite3_int64 sqlite3_uri_int64(
const char *zFilename, /* Filename as passed to xOpen */
const char *zParam, /* URI parameter sought */
sqlite3_int64 bDflt /* return if parameter is missing */
){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
sqlite3_int64 v;
if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
bDflt = v;
}
return bDflt;
}
/*
** Return the Btree pointer identified by zDbName. Return NULL if not found.
|
| ︙ | ︙ | |||
126281 126282 126283 126284 126285 126286 126287 | SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); /* fts3_tokenize_vtab.c */ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); /* fts3_unicode2.c (functions generated by parsing unicode text files) */ | | | 127104 127105 127106 127107 127108 127109 127110 127111 127112 127113 127114 127115 127116 127117 127118 | SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); /* fts3_tokenize_vtab.c */ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); /* fts3_unicode2.c (functions generated by parsing unicode text files) */ #ifndef SQLITE_DISABLE_FTS3_UNICODE SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int); SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int); SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int); #endif #endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ #endif /* _FTSINT_H */ |
| ︙ | ︙ | |||
129751 129752 129753 129754 129755 129756 129757 | ** ** Calling sqlite3Fts3SimpleTokenizerModule() sets the value pointed ** to by the argument to point to the "simple" tokenizer implementation. ** And so on. */ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); | | | | | 130574 130575 130576 130577 130578 130579 130580 130581 130582 130583 130584 130585 130586 130587 130588 130589 130590 130591 130592 130593 130594 130595 130596 130597 130598 130599 130600 130601 130602 130603 130604 130605 130606 130607 130608 130609 130610 130611 130612 130613 130614 130615 |
**
** Calling sqlite3Fts3SimpleTokenizerModule() sets the value pointed
** to by the argument to point to the "simple" tokenizer implementation.
** And so on.
*/
SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule);
SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule);
#ifndef SQLITE_DISABLE_FTS3_UNICODE
SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule);
#endif
#ifdef SQLITE_ENABLE_ICU
SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule);
#endif
/*
** Initialize the fts3 extension. If this extension is built as part
** of the sqlite library, then this function is called directly by
** SQLite. If fts3 is built as a dynamically loadable extension, this
** function is called by the sqlite3_extension_init() entry point.
*/
SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
int rc = SQLITE_OK;
Fts3Hash *pHash = 0;
const sqlite3_tokenizer_module *pSimple = 0;
const sqlite3_tokenizer_module *pPorter = 0;
#ifndef SQLITE_DISABLE_FTS3_UNICODE
const sqlite3_tokenizer_module *pUnicode = 0;
#endif
#ifdef SQLITE_ENABLE_ICU
const sqlite3_tokenizer_module *pIcu = 0;
sqlite3Fts3IcuTokenizerModule(&pIcu);
#endif
#ifndef SQLITE_DISABLE_FTS3_UNICODE
sqlite3Fts3UnicodeTokenizer(&pUnicode);
#endif
#ifdef SQLITE_TEST
rc = sqlite3Fts3InitTerm(db);
if( rc!=SQLITE_OK ) return rc;
#endif
|
| ︙ | ︙ | |||
129806 129807 129808 129809 129810 129811 129812 |
}
/* Load the built-in tokenizers into the hash table */
if( rc==SQLITE_OK ){
if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple)
|| sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter)
| | | 130629 130630 130631 130632 130633 130634 130635 130636 130637 130638 130639 130640 130641 130642 130643 |
}
/* Load the built-in tokenizers into the hash table */
if( rc==SQLITE_OK ){
if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple)
|| sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter)
#ifndef SQLITE_DISABLE_FTS3_UNICODE
|| sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode)
#endif
#ifdef SQLITE_ENABLE_ICU
|| (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu))
#endif
){
rc = SQLITE_NOMEM;
|
| ︙ | ︙ | |||
143066 143067 143068 143069 143070 143071 143072 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** Implementation of the "unicode" full-text-search tokenizer. */ | | | 143889 143890 143891 143892 143893 143894 143895 143896 143897 143898 143899 143900 143901 143902 143903 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** Implementation of the "unicode" full-text-search tokenizer. */ #ifndef SQLITE_DISABLE_FTS3_UNICODE #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <assert.h> */ /* #include <stdlib.h> */ /* #include <stdio.h> */ /* #include <string.h> */ |
| ︙ | ︙ | |||
143282 143283 143284 143285 143286 143287 143288 |
pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer));
if( pNew==NULL ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(unicode_tokenizer));
pNew->bRemoveDiacritic = 1;
for(i=0; rc==SQLITE_OK && i<nArg; i++){
const char *z = azArg[i];
| | | 144105 144106 144107 144108 144109 144110 144111 144112 144113 144114 144115 144116 144117 144118 144119 |
pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer));
if( pNew==NULL ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(unicode_tokenizer));
pNew->bRemoveDiacritic = 1;
for(i=0; rc==SQLITE_OK && i<nArg; i++){
const char *z = azArg[i];
int n = (int)strlen(z);
if( n==19 && memcmp("remove_diacritics=1", z, 19)==0 ){
pNew->bRemoveDiacritic = 1;
}
else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){
pNew->bRemoveDiacritic = 0;
}
|
| ︙ | ︙ | |||
143369 143370 143371 143372 143373 143374 143375 |
int *pnToken, /* OUT: Number of bytes at *paToken */
int *piStart, /* OUT: Starting offset of token */
int *piEnd, /* OUT: Ending offset of token */
int *piPos /* OUT: Position integer of token */
){
unicode_cursor *pCsr = (unicode_cursor *)pC;
unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer);
| | | 144192 144193 144194 144195 144196 144197 144198 144199 144200 144201 144202 144203 144204 144205 144206 |
int *pnToken, /* OUT: Number of bytes at *paToken */
int *piStart, /* OUT: Starting offset of token */
int *piEnd, /* OUT: Ending offset of token */
int *piPos /* OUT: Position integer of token */
){
unicode_cursor *pCsr = (unicode_cursor *)pC;
unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer);
int iCode = 0;
char *zOut;
const unsigned char *z = &pCsr->aInput[pCsr->iOff];
const unsigned char *zStart = z;
const unsigned char *zEnd;
const unsigned char *zTerm = &pCsr->aInput[pCsr->nInput];
/* Scan past any delimiter characters before the start of the next token.
|
| ︙ | ︙ | |||
143414 143415 143416 143417 143418 143419 143420 |
if( z>=zTerm ) break;
READ_UTF8(z, zTerm, iCode);
}while( unicodeIsAlnum(p, iCode)
|| sqlite3FtsUnicodeIsdiacritic(iCode)
);
/* Set the output variables and return. */
| | | | | | 144237 144238 144239 144240 144241 144242 144243 144244 144245 144246 144247 144248 144249 144250 144251 144252 144253 144254 144255 |
if( z>=zTerm ) break;
READ_UTF8(z, zTerm, iCode);
}while( unicodeIsAlnum(p, iCode)
|| sqlite3FtsUnicodeIsdiacritic(iCode)
);
/* Set the output variables and return. */
pCsr->iOff = (int)(z - pCsr->aInput);
*paToken = pCsr->zToken;
*pnToken = (int)(zOut - pCsr->zToken);
*piStart = (int)(zStart - pCsr->aInput);
*piEnd = (int)(zEnd - pCsr->aInput);
*piPos = pCsr->iToken++;
return SQLITE_OK;
}
/*
** Set *ppModule to a pointer to the sqlite3_tokenizer_module
** structure for the unicode tokenizer.
|
| ︙ | ︙ | |||
143441 143442 143443 143444 143445 143446 143447 |
unicodeNext,
0,
};
*ppModule = &module;
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
| | | | 144264 144265 144266 144267 144268 144269 144270 144271 144272 144273 144274 144275 144276 144277 144278 144279 144280 144281 144282 144283 144284 144285 144286 144287 144288 144289 144290 144291 144292 144293 144294 144295 144296 144297 144298 144299 |
unicodeNext,
0,
};
*ppModule = &module;
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
#endif /* ifndef SQLITE_DISABLE_FTS3_UNICODE */
/************** End of fts3_unicode.c ****************************************/
/************** Begin file fts3_unicode2.c ***********************************/
/*
** 2012 May 25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
*/
/*
** DO NOT EDIT THIS MACHINE GENERATED FILE.
*/
#ifndef SQLITE_DISABLE_FTS3_UNICODE
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
/* #include <assert.h> */
/*
** Return true if the argument corresponds to a unicode codepoint
** classified as either a letter or a number. Otherwise false.
|
| ︙ | ︙ | |||
143486 143487 143488 143489 143490 143491 143492 | ** 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. */ | | | 144309 144310 144311 144312 144313 144314 144315 144316 144317 144318 144319 144320 144321 144322 144323 |
** 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,
|
| ︙ | ︙ | |||
143578 143579 143580 143581 143582 143583 143584 |
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
};
if( c<128 ){
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
}else if( c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
| | | 144401 144402 144403 144404 144405 144406 144407 144408 144409 144410 144411 144412 144413 144414 144415 |
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
};
if( c<128 ){
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
}else if( c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
int iRes = 0;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
while( iHi>=iLo ){
int iTest = (iHi + iLo) / 2;
if( key >= aEntry[iTest] ){
iRes = iTest;
iLo = iTest+1;
|
| ︙ | ︙ | |||
143649 143650 143651 143652 143653 143654 143655 |
iLo = iTest+1;
}else{
iHi = iTest-1;
}
}
assert( key>=aDia[iRes] );
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
| < > | 144472 144473 144474 144475 144476 144477 144478 144479 144480 144481 144482 144483 144484 144485 144486 |
iLo = iTest+1;
}else{
iHi = iTest-1;
}
}
assert( key>=aDia[iRes] );
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
}
/*
** Return true if the argument interpreted as a unicode codepoint
** is a diacritical modifier character.
*/
SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){
|
| ︙ | ︙ | |||
143809 143810 143811 143812 143813 143814 143815 |
else if( c>=66560 && c<66600 ){
ret = c + 40;
}
return ret;
}
#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */
| | | 144632 144633 144634 144635 144636 144637 144638 144639 144640 144641 144642 144643 144644 144645 144646 |
else if( c>=66560 && c<66600 ){
ret = c + 40;
}
return ret;
}
#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */
#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */
/************** End of fts3_unicode2.c ***************************************/
/************** Begin file rtree.c *******************************************/
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
|
| ︙ | ︙ | |||
145346 145347 145348 145349 145350 145351 145352 145353 | RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; int iCell = 0; rtreeReference(pRtree); freeCursorConstraints(pCsr); | > | > > > | 146169 146170 146171 146172 146173 146174 146175 146176 146177 146178 146179 146180 146181 146182 146183 146184 146185 146186 146187 146188 146189 |
RtreeNode *pRoot = 0;
int ii;
int rc = SQLITE_OK;
int iCell = 0;
rtreeReference(pRtree);
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
freeCursorConstraints(pCsr);
sqlite3_free(pCsr->aPoint);
memset(pCsr, 0, sizeof(RtreeCursor));
pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
pCsr->iStrategy = idxNum;
if( idxNum==1 ){
/* Special case - lookup by rowid. */
RtreeNode *pLeaf; /* Leaf on which the required cell resides */
RtreeSearchPoint *p; /* Search point for the the leaf */
i64 iRowid = sqlite3_value_int64(argv[0]);
i64 iNode = 0;
rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
|
| ︙ | ︙ |
Changes to src/sqlite3.h.
| ︙ | ︙ | |||
105 106 107 108 109 110 111 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.6" #define SQLITE_VERSION_NUMBER 3008006 | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.6" #define SQLITE_VERSION_NUMBER 3008006 #define SQLITE_SOURCE_ID "2014-08-12 16:13:37 6715991296886c2a02b9a285a1e61189ad1f79c0" /* ** 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 |
| ︙ | ︙ | |||
265 266 267 268 269 270 271 | #endif /* ** CAPI3REF: Closing A Database Connection ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. | | | | | 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 | #endif /* ** CAPI3REF: Closing A Database Connection ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. ** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** ** ^If the database connection is associated with unfinalized prepared ** statements or unfinished sqlite3_backup objects then sqlite3_close() ** will leave the database connection open and return [SQLITE_BUSY]. ** ^If sqlite3_close_v2() is called with unfinalized prepared statements ** and/or unfinished sqlite3_backups, then the database connection becomes ** an unusable "zombie" which will automatically be deallocated when the ** last prepared statement is finalized or the last sqlite3_backup is ** finished. The sqlite3_close_v2() interface is intended for use with ** host languages that are garbage collected, and where the order in which ** destructors are called is arbitrary. ** ** Applications should [sqlite3_finalize | finalize] all [prepared statements], ** [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated ** with the [sqlite3] object prior to attempting to close the object. ^If ** sqlite3_close_v2() is called on a [database connection] that still has ** outstanding [prepared statements], [BLOB handles], and/or ** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation ** of resources is deferred until all [prepared statements], [BLOB handles], ** and [sqlite3_backup] objects are also destroyed. ** ** ^If an [sqlite3] object is destroyed while a transaction is open, ** the transaction is automatically rolled back. ** ** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)] |
| ︙ | ︙ | |||
382 383 384 385 386 387 388 | int (*callback)(void*,int,char**,char**), /* Callback function */ void *, /* 1st argument to callback */ char **errmsg /* Error msg written here */ ); /* ** CAPI3REF: Result Codes | < | | < | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);
/*
** CAPI3REF: Result Codes
** KEYWORDS: {result code definitions}
**
** Many SQLite functions return an integer result code from the set shown
** here in order to indicate success or failure.
**
** New error codes may be added in future versions of SQLite.
**
** See also: [extended result code definitions]
*/
#define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
| ︙ | ︙ | |||
429 430 431 432 433 434 435 | #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ /* end-of-error-codes */ /* ** CAPI3REF: Extended Result Codes | < | | | | | | | < < < < < < | 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 |
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */
/*
** CAPI3REF: Extended Result Codes
** KEYWORDS: {extended result code definitions}
**
** In its default configuration, SQLite API routines return one of 30 integer
** [result codes]. However, experience has shown that many of
** these result codes are too coarse-grained. They do not provide as
** much information about problems as programmers might like. In an effort to
** 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. These [extended result codes] are enabled or disabled
** on a per database connection basis using the
** [sqlite3_extended_result_codes()] API. Or, the extended code for
** the most recent error can be obtained using
** [sqlite3_extended_errcode()].
*/
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))
#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))
|
| ︙ | ︙ | |||
681 682 683 684 685 686 687 | ** integer opcode. The third argument is a generic pointer intended to ** point to a structure that may contain arguments or space in which to ** write return values. Potential uses for xFileControl() might be ** functions to enable blocking locks with timeouts, to change the ** locking strategy (for example to use dot-file locks), to inquire ** about the status of a lock, or to break stale locks. The SQLite ** core reserves all opcodes less than 100 for its own use. | | | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 | ** integer opcode. The third argument is a generic pointer intended to ** point to a structure that may contain arguments or space in which to ** write return values. Potential uses for xFileControl() might be ** functions to enable blocking locks with timeouts, to change the ** locking strategy (for example to use dot-file locks), to inquire ** about the status of a lock, or to break stale locks. The SQLite ** core reserves all opcodes less than 100 for its own use. ** A [file control opcodes | list of opcodes] less than 100 is available. ** Applications that define a custom xFileControl method should use opcodes ** greater than 100 to avoid conflicts. VFS implementations should ** return [SQLITE_NOTFOUND] for file control opcodes that they do not ** recognize. ** ** The xSectorSize() method returns the sector size of the ** device that underlies the file. The sector size is the |
| ︙ | ︙ | |||
754 755 756 757 758 759 760 761 762 763 764 765 766 767 | int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); /* Methods above are valid for version 3 */ /* Additional methods may be added in future releases */ }; /* ** CAPI3REF: Standard File Control Opcodes ** ** These integer constants are opcodes for the xFileControl method ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] ** interface. ** ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of | > | 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 |
int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);
/* Methods above are valid for version 3 */
/* Additional methods may be added in future releases */
};
/*
** CAPI3REF: Standard File Control Opcodes
** KEYWORDS: {file control opcodes} {file control opcode}
**
** These integer constants are opcodes for the xFileControl method
** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
** interface.
**
** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
** opcode causes the xFileControl method to write the current state of
|
| ︙ | ︙ | |||
2033 2034 2035 2036 2037 2038 2039 | */ SQLITE_API int sqlite3_complete(const char *sql); SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** | | > | > | > > | | | > | | > < < < < < < < < < < < < < < < > | | > | > > | 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 | */ SQLITE_API int sqlite3_complete(const char *sql); SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** ** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X ** that might be invoked with argument P whenever ** an attempt is made to access a database table associated with ** [database connection] D when another thread ** or process has the table locked. ** The sqlite3_busy_handler() interface is used to implement ** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. ** ** ^If the busy callback is NULL, then [SQLITE_BUSY] ** is returned immediately upon encountering the lock. ^If the busy callback ** is not NULL, then the callback might be invoked with two arguments. ** ** ^The first argument to the busy handler is a copy of the void* pointer which ** is the third argument to sqlite3_busy_handler(). ^The second argument to ** the busy handler callback is the number of times that the busy handler has ** been invoked for the same locking event. ^If the ** busy callback returns 0, then no additional attempts are made to ** access the database and [SQLITE_BUSY] is returned ** to the application. ** ^If the callback returns non-zero, then another attempt ** is made to access the database and the cycle repeats. ** ** The presence of a busy handler does not guarantee that it will be invoked ** when there is lock contention. ^If SQLite determines that invoking the busy ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] ** to the application instead of invoking the ** busy handler. ** Consider a scenario where one process is holding a read lock that ** it is trying to promote to a reserved lock and ** a second process is holding a reserved lock that it is trying ** to promote to an exclusive lock. The first process cannot proceed ** because it is blocked by the second and the second process cannot ** proceed because it is blocked by the first. If both processes ** invoke the busy handlers, neither will make any progress. Therefore, ** SQLite returns [SQLITE_BUSY] for the first process, hoping that this ** will induce the first process to release its read lock and allow ** the second process to proceed. ** ** ^The default busy callback is NULL. ** ** ^(There can only be a single busy handler defined for each ** [database connection]. Setting a new busy handler clears any ** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] ** or evaluating [PRAGMA busy_timeout=N] will change the ** busy handler and thus clear any previously set busy handler. ** ** The busy callback should not take any actions which modify the ** database connection that invoked the busy handler. In other words, ** the busy handler is not reentrant. Any such actions ** result in undefined behavior. ** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); /* ** CAPI3REF: Set A Busy Timeout ** ** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps ** for a specified amount of time when a table is locked. ^The handler ** will sleep multiple times until at least "ms" milliseconds of sleeping ** have accumulated. ^After at least "ms" milliseconds of sleeping, ** the handler returns 0 which causes [sqlite3_step()] to return ** [SQLITE_BUSY]. ** ** ^Calling this routine with an argument less than or equal to zero ** turns off all busy handlers. ** ** ^(There can only be a single busy handler for a particular ** [database connection] any any given moment. If another busy handler ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ ** ** See also: [PRAGMA busy_timeout] */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Convenience Routines For Running Queries ** ** This is a legacy interface that is preserved for backwards compatibility. |
| ︙ | ︙ | |||
2514 2515 2516 2517 2518 2519 2520 | ** ** The [sqlite3_set_authorizer | authorizer callback function] must ** return either [SQLITE_OK] or one of these two constants in order ** to signal SQLite whether or not the action is permitted. See the ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. ** | | | | 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 | ** ** The [sqlite3_set_authorizer | authorizer callback function] must ** return either [SQLITE_OK] or one of these two constants in order ** to signal SQLite whether or not the action is permitted. See the ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. ** ** Note that SQLITE_IGNORE is also used as a [conflict resolution mode] ** returned from the [sqlite3_vtab_on_conflict()] interface. */ #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ /* ** CAPI3REF: Authorizer Action Codes ** |
| ︙ | ︙ | |||
4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 | ** ** ^(If this global variable is made to point to a string which is ** the name of a folder (a.k.a. directory), then all temporary files ** created by SQLite when using a built-in [sqlite3_vfs | VFS] ** will be placed in that directory.)^ ^If this variable ** is a NULL pointer, then SQLite performs a search for an appropriate ** temporary file directory. ** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate ** thread. ** It is intended that this variable be set once ** as part of process initialization and before any SQLite interface ** routines have been called and that this variable remain unchanged ** thereafter. ** ** ^The [temp_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [temp_store_directory pragma] always assumes that any string ** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [temp_store_directory pragma] should be avoided. ** ** <b>Note to Windows Runtime users:</b> The temporary directory must be set ** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various ** features that require the use of temporary files may fail. Here is an ** example of how to do this using C++ with the Windows Runtime: ** ** <blockquote><pre> | > > > > > > > > > > > > | 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 | ** ** ^(If this global variable is made to point to a string which is ** the name of a folder (a.k.a. directory), then all temporary files ** created by SQLite when using a built-in [sqlite3_vfs | VFS] ** will be placed in that directory.)^ ^If this variable ** is a NULL pointer, then SQLite performs a search for an appropriate ** temporary file directory. ** ** Applications are strongly discouraged from using this global variable. ** It is required to set a temporary folder on Windows Runtime (WinRT). ** But for all other platforms, it is highly recommended that applications ** neither read nor write this variable. This global variable is a relic ** that exists for backwards compatibility of legacy applications and should ** be avoided in new projects. ** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate ** thread. ** It is intended that this variable be set once ** as part of process initialization and before any SQLite interface ** routines have been called and that this variable remain unchanged ** thereafter. ** ** ^The [temp_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [temp_store_directory pragma] always assumes that any string ** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [temp_store_directory pragma] should be avoided. ** Except when requested by the [temp_store_directory pragma], SQLite ** does not free the memory that sqlite3_temp_directory points to. If ** the application wants that memory to be freed, it must do ** so itself, taking care to only do so after all [database connection] ** objects have been destroyed. ** ** <b>Note to Windows Runtime users:</b> The temporary directory must be set ** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various ** features that require the use of temporary files may fail. Here is an ** example of how to do this using C++ with the Windows Runtime: ** ** <blockquote><pre> |
| ︙ | ︙ | |||
5854 5855 5856 5857 5858 5859 5860 | ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM | | | > > | 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 | ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_OPEN ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_PMEM ** <li> SQLITE_MUTEX_STATIC_APP1 ** <li> SQLITE_MUTEX_STATIC_APP2 ** </ul>)^ ** ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) ** cause sqlite3_mutex_alloc() to create ** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction |
| ︙ | ︙ | |||
6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 | #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ #define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ /* ** CAPI3REF: Retrieve the mutex for a database connection ** ** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. | > > > | 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 | #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ #define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ #define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ #define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ #define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ /* ** CAPI3REF: Retrieve the mutex for a database connection ** ** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. |
| ︙ | ︙ | |||
6156 6157 6158 6159 6160 6161 6162 | #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_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 | > | | 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 | #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_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_LAST 23 /* ** 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 |
| ︙ | ︙ | |||
7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 | ** ^The callback registered by this function replaces any existing callback ** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback ** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism ** configured by this function. ** ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface ** from SQL. ** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] ** pages. The use of this interface ** is only necessary if the default setting is found to be suboptimal ** for a particular application. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database ** ** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X ** on [database connection] D to be [checkpointed]. ^If X is NULL or an ** empty string, then a checkpoint is run on all databases of ** connection D. ^If the database connection D is not in ** [WAL | write-ahead log mode] then this interface is a harmless no-op. ** ** ^The [wal_checkpoint pragma] can be used to invoke this interface ** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] can be used to cause this interface to be ** run whenever the WAL reaches a certain size threshold. ** ** See also: [sqlite3_wal_checkpoint_v2()] | > > > > > > > | 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 | ** ^The callback registered by this function replaces any existing callback ** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback ** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism ** configured by this function. ** ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface ** from SQL. ** ** ^Checkpoints initiated by this mechanism are ** [sqlite3_wal_checkpoint_v2|PASSIVE]. ** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] ** pages. The use of this interface ** is only necessary if the default setting is found to be suboptimal ** for a particular application. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database ** ** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X ** on [database connection] D to be [checkpointed]. ^If X is NULL or an ** empty string, then a checkpoint is run on all databases of ** connection D. ^If the database connection D is not in ** [WAL | write-ahead log mode] then this interface is a harmless no-op. ** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a ** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint. ** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL ** or RESET checkpoint. ** ** ^The [wal_checkpoint pragma] can be used to invoke this interface ** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] can be used to cause this interface to be ** run whenever the WAL reaches a certain size threshold. ** ** See also: [sqlite3_wal_checkpoint_v2()] |
| ︙ | ︙ | |||
7178 7179 7180 7181 7182 7183 7184 | ** eMode parameter: ** ** <dl> ** <dt>SQLITE_CHECKPOINT_PASSIVE<dd> ** Checkpoint as many frames as possible without waiting for any database ** readers or writers to finish. Sync the db file if all frames in the log ** are checkpointed. This mode is the same as calling | | > | > | > | 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 | ** eMode parameter: ** ** <dl> ** <dt>SQLITE_CHECKPOINT_PASSIVE<dd> ** Checkpoint as many frames as possible without waiting for any database ** readers or writers to finish. Sync the db file if all frames in the log ** are checkpointed. This mode is the same as calling ** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback] ** is never invoked. ** ** <dt>SQLITE_CHECKPOINT_FULL<dd> ** This mode blocks (it invokes the ** [sqlite3_busy_handler|busy-handler callback]) until there is no ** database writer and all readers are reading from the most recent database ** snapshot. It then checkpoints all frames in the log file and syncs the ** database file. This call blocks database writers while it is running, ** but not database readers. ** ** <dt>SQLITE_CHECKPOINT_RESTART<dd> ** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after ** checkpointing the log file it blocks (calls the ** [sqlite3_busy_handler|busy-handler callback]) ** until all readers are reading from the database file only. This ensures ** that the next client to write to the database file restarts the log file ** from the beginning. This call blocks database writers while it is running, ** but not database readers. ** </dl> ** ** If pnLog is not NULL, then *pnLog is set to the total number of frames in |
| ︙ | ︙ | |||
7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 | ** of the SQL statement that triggered the call to the [xUpdate] method of the ** [virtual table]. */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Conflict resolution modes ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to ** inform a [virtual table] implementation what the [ON CONFLICT] mode ** is for the SQL statement being evaluated. ** ** Note that the [SQLITE_IGNORE] constant is also used as a potential ** return value from the [sqlite3_set_authorizer()] callback and that | > | 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 |
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode}
**
** These constants are returned by [sqlite3_vtab_on_conflict()] to
** inform a [virtual table] implementation what the [ON CONFLICT] mode
** is for the SQL statement being evaluated.
**
** Note that the [SQLITE_IGNORE] constant is also used as a potential
** return value from the [sqlite3_set_authorizer()] callback and that
|
| ︙ | ︙ |
Changes to src/stat.c.
| ︙ | ︙ | |||
170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
int brief;
char zBuf[100];
const int colWidth = -19 /* printf alignment/width for left column */;
const char *p;
brief = find_option("brief", "b",0)!=0;
db_find_and_open_repository(0,0);
fsize = file_size(g.zRepositoryName);
bigSizeName(sizeof(zBuf), zBuf, fsize);
fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf );
if( !brief ){
n = db_int(0, "SELECT count(*) FROM blob");
m = db_int(0, "SELECT count(*) FROM delta");
fossil_print("%*s%d (stored as %d full text and %d delta blobs)\n",
| > > > > | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
int brief;
char zBuf[100];
const int colWidth = -19 /* printf alignment/width for left column */;
const char *p;
brief = find_option("brief", "b",0)!=0;
db_find_and_open_repository(0,0);
/* We should be done with options.. */
verify_all_options();
fsize = file_size(g.zRepositoryName);
bigSizeName(sizeof(zBuf), zBuf, fsize);
fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf );
if( !brief ){
n = db_int(0, "SELECT count(*) FROM blob");
m = db_int(0, "SELECT count(*) FROM delta");
fossil_print("%*s%d (stored as %d full text and %d delta blobs)\n",
|
| ︙ | ︙ |
Changes to src/sync.c.
| ︙ | ︙ | |||
184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
**
** See also: clone, push, sync, remote-url
*/
void pull_cmd(void){
unsigned configFlags = 0;
unsigned syncFlags = SYNC_PULL;
process_sync_args(&configFlags, &syncFlags);
client_sync(syncFlags, configFlags, 0);
}
/*
** COMMAND: push
**
** Usage: %fossil push ?URL? ?options?
| > > > > | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
**
** See also: clone, push, sync, remote-url
*/
void pull_cmd(void){
unsigned configFlags = 0;
unsigned syncFlags = SYNC_PULL;
process_sync_args(&configFlags, &syncFlags);
/* We should be done with options.. */
verify_all_options();
client_sync(syncFlags, configFlags, 0);
}
/*
** COMMAND: push
**
** Usage: %fossil push ?URL? ?options?
|
| ︙ | ︙ | |||
215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
**
** See also: clone, pull, sync, remote-url
*/
void push_cmd(void){
unsigned configFlags = 0;
unsigned syncFlags = SYNC_PUSH;
process_sync_args(&configFlags, &syncFlags);
if( db_get_boolean("dont-push",0) ){
fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
}
client_sync(syncFlags, 0, 0);
}
| > > > > | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
**
** See also: clone, pull, sync, remote-url
*/
void push_cmd(void){
unsigned configFlags = 0;
unsigned syncFlags = SYNC_PUSH;
process_sync_args(&configFlags, &syncFlags);
/* We should be done with options.. */
verify_all_options();
if( db_get_boolean("dont-push",0) ){
fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
}
client_sync(syncFlags, 0, 0);
}
|
| ︙ | ︙ | |||
251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
**
** See also: clone, push, pull, remote-url
*/
void sync_cmd(void){
unsigned configFlags = 0;
unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
process_sync_args(&configFlags, &syncFlags);
if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
client_sync(syncFlags, configFlags, 0);
if( (syncFlags & SYNC_PUSH)==0 ){
fossil_warning("pull only: the 'dont-push' option is set");
}
}
| > > > > | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
**
** See also: clone, push, pull, remote-url
*/
void sync_cmd(void){
unsigned configFlags = 0;
unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
process_sync_args(&configFlags, &syncFlags);
/* We should be done with options.. */
verify_all_options();
if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
client_sync(syncFlags, configFlags, 0);
if( (syncFlags & SYNC_PUSH)==0 ){
fossil_warning("pull only: the 'dont-push' option is set");
}
}
|
| ︙ | ︙ | |||
278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
** 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);
db_unset("http-auth", 0);
| > > > > | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
** 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);
/* We should be done with options.. */
verify_all_options();
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);
db_unset("http-auth", 0);
|
| ︙ | ︙ |
Changes to src/tag.c.
| ︙ | ︙ | |||
48 49 50 51 52 53 54 | pqueuex_init(&queue); pqueuex_insert(&queue, pid, 0.0, 0); /* Query for children of :pid to which to propagate the tag. ** Three returns: (1) rid of the child. (2) timestamp of child. ** (3) True to propagate or false to block. */ | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
pqueuex_init(&queue);
pqueuex_insert(&queue, pid, 0.0, 0);
/* Query for children of :pid to which to propagate the tag.
** Three returns: (1) rid of the child. (2) timestamp of child.
** (3) True to propagate or false to block.
*/
db_prepare(&s,
"SELECT cid, plink.mtime,"
" coalesce(srcid=0 AND tagxref.mtime<:mtime, %d) AS doit"
" FROM plink LEFT JOIN tagxref ON cid=rid AND tagid=%d"
" WHERE pid=:pid AND isprim",
tagType==2, tagid
);
db_bind_double(&s, ":mtime", mtime);
|
| ︙ | ︙ | |||
177 178 179 180 181 182 183 |
db_bind_double(&s, ":mtime", mtime);
rc = db_step(&s);
db_finalize(&s);
if( rc==SQLITE_ROW ){
/* Another entry that is more recent already exists. Do nothing */
return tagid;
}
| | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
db_bind_double(&s, ":mtime", mtime);
rc = db_step(&s);
db_finalize(&s);
if( rc==SQLITE_ROW ){
/* Another entry that is more recent already exists. Do nothing */
return tagid;
}
db_prepare(&s,
"REPLACE INTO tagxref(tagid,tagtype,srcId,origid,value,mtime,rid)"
" VALUES(%d,%d,%d,%d,%Q,:mtime,%d)",
tagid, tagtype, srcId, rid, zValue, rid
);
db_bind_double(&s, ":mtime", mtime);
db_step(&s);
db_finalize(&s);
|
| ︙ | ︙ | |||
254 255 256 257 258 259 260 |
usage("TAGNAME ARTIFACT-ID ?VALUE?");
}
zTag = g.argv[2];
switch( zTag[0] ){
case '+': tagtype = 1; break;
case '*': tagtype = 2; break;
case '-': tagtype = 0; break;
| | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
usage("TAGNAME ARTIFACT-ID ?VALUE?");
}
zTag = g.argv[2];
switch( zTag[0] ){
case '+': tagtype = 1; break;
case '*': tagtype = 2; break;
case '-': tagtype = 0; break;
default:
fossil_fatal("tag should begin with '+', '*', or '-'");
return;
}
rid = name_to_rid(g.argv[3]);
if( rid==0 ){
fossil_fatal("no such object: %s", g.argv[3]);
}
|
| ︙ | ︙ | |||
376 377 378 379 380 381 382 | ** will be taken as an artifact or baseline ID and fossil will ** probably complain that no such revision was found. However ** ** fossil update tag:decaf ** ** will assume that "decaf" is a tag/branch name. ** | | | | | | 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 |
** will be taken as an artifact or baseline ID and fossil will
** probably complain that no such revision was found. However
**
** fossil update tag:decaf
**
** will assume that "decaf" is a tag/branch name.
**
** only allow --date-override and --user-override in
** %fossil tag add --date-override 'YYYY-MMM-DD HH:MM:SS' \\
** --user-override user
** 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-";
const char *zFindLimit = find_option("limit","n",1);
const int 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 ){
|
| ︙ | ︙ | |||
476 477 478 479 480 481 482 |
}
}
}else
if( strncmp(g.argv[2],"list",n)==0 ){
Stmt q;
if( g.argc==3 ){
| | | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
}
}
}else
if( strncmp(g.argv[2],"list",n)==0 ){
Stmt q;
if( g.argc==3 ){
db_prepare(&q,
"SELECT tagname FROM tag"
" WHERE EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=tag.tagid"
" AND tagtype>0)"
" ORDER BY tagname"
);
while( db_step(&q)==SQLITE_ROW ){
|
| ︙ | ︙ |
Changes to src/tar.c.
| ︙ | ︙ | |||
524 525 526 527 528 529 530 | blob_reset(&filename); tar_finish(pTar); } /* ** COMMAND: tarball* ** | | > > > > > > > > | 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 |
blob_reset(&filename);
tar_finish(pTar);
}
/*
** COMMAND: tarball*
**
** Usage: %fossil tarball VERSION OUTPUTFILE
**
** Generate a compressed tarball for a specified version. If the --name
** option is used, its argument becomes the name of the top-level directory
** in the resulting tarball. If --name is omitted, the top-level directory
** named is derived from the project name, the check-in date and time, and
** the artifact ID of the check-in.
**
** Options:
** --name DIRECTORYNAME The name of the top-level directory in the archive
** -R REPOSITORY Specify a Fossil repository
*/
void tarball_cmd(void){
int rid;
Blob tarball;
const char *zName;
zName = find_option("name", 0, 1);
db_find_and_open_repository(0, 0);
/* We should be done with options.. */
verify_all_options();
if( g.argc!=4 ){
usage("VERSION OUTPUTFILE");
}
rid = name_to_typed_rid(g.argv[2], "ci");
if( rid==0 ){
fossil_fatal("Checkin not found: %s", g.argv[2]);
return;
|
| ︙ | ︙ | |||
572 573 574 575 576 577 578 | ** URL: /tarball/RID.tar.gz ** ** Generate a compressed tarball for a checkin. ** Return that tarball as the HTTP reply content. ** ** Optional URL Parameters: ** | | | > > | | 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 |
** URL: /tarball/RID.tar.gz
**
** Generate a compressed tarball for a checkin.
** Return that tarball as the HTTP reply content.
**
** Optional URL Parameters:
**
** - name=NAME[.tar.gz] is base name of the output file. Defaults to
** something project/version-specific. The prefix of the name, up to
** the last '.', are used as the top-most directory name in the tar
** output.
**
** - uuid=the version to tar (may be a tag/branch name).
** Defaults to "trunk".
**
*/
void tarball_page(void){
int rid;
char *zName, *zRid, *zKey;
int nName, nRid;
Blob tarball;
|
| ︙ | ︙ | |||
612 613 614 615 616 617 618 |
}
rid = name_to_typed_rid(nRid?zRid:zName, "ci");
if( rid==0 ){
@ Not found
return;
}
if( nRid==0 && nName>10 ) zName[10] = 0;
| | > > > > > > > > > | 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 |
}
rid = name_to_typed_rid(nRid?zRid:zName, "ci");
if( rid==0 ){
@ Not found
return;
}
if( nRid==0 && nName>10 ) zName[10] = 0;
zKey = db_text(0, "SELECT '/tarball/'||uuid||'/%q'"
" FROM blob WHERE rid=%d",zName,rid);
if( P("debug")!=0 ){
style_header("Tarball Generator Debug Screen");
@ zName = "%h(zName)"<br>
@ rid = %d(rid)<br>
@ zKey = "%h(zKey)"
style_footer();
return;
}
blob_zero(&tarball);
if( cache_read(&tarball, zKey)==0 ){
tarball_of_checkin(rid, &tarball, zName);
cache_write(&tarball, zKey);
}
free( zName );
free( zRid );
free( zKey );
cgi_set_content(&tarball);
cgi_set_content_type("application/x-compressed");
}
|
Changes to src/th.c.
| ︙ | ︙ | |||
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 |
case '[': if( nBrace==0 ) nSq++; break;
case ']': if( nBrace==0 ) nSq--; break;
}
iEnd++;
}
if( nBrace>0 || nSq>0 ){
/* Parse error */
return TH_ERROR;
}
}
if( iEnd>nInput ){
/* Parse error */
return TH_ERROR;
}
*pnWord = iEnd;
return TH_OK;
}
/*
| > > | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
case '[': if( nBrace==0 ) nSq++; break;
case ']': if( nBrace==0 ) nSq--; break;
}
iEnd++;
}
if( nBrace>0 || nSq>0 ){
/* Parse error */
Th_SetResult(interp, "parse error", -1);
return TH_ERROR;
}
}
if( iEnd>nInput ){
/* Parse error */
Th_SetResult(interp, "parse error", -1);
return TH_ERROR;
}
*pnWord = iEnd;
return TH_OK;
}
/*
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
994 995 996 997 998 999 1000 | ** n=COUNT max number of events in output ** p=UUID artifact and up to COUNT parents and ancestors ** d=UUID artifact and up to COUNT descendants ** dp=UUID The same as d=UUID&p=UUID ** t=TAGID show only check-ins with the given tagid ** r=TAGID show check-ins related to tagid ** u=USER only if belonging to this user | | > | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 | ** n=COUNT max number of events in output ** p=UUID artifact and up to COUNT parents and ancestors ** d=UUID artifact and up to COUNT descendants ** dp=UUID The same as d=UUID&p=UUID ** t=TAGID show only check-ins with the given tagid ** r=TAGID show check-ins related to tagid ** u=USER only if belonging to this user ** y=TYPE 'ci', 'w', 't', 'e', or (default) 'all' ** s=TEXT string search (comment and brief) ** ng Suppress the graph if present ** nd Suppress "divider" lines ** v Show details of files changed ** f=UUID Show family (immediate parents and children) of UUID ** from=UUID Path from... ** to=UUID ... to this ** nomerge ... avoid merge links on the path ** shortest ... show only the shortest path ** uf=FUUID Show only checkins that use given file version ** brbg Background color from branch name ** ubg Background color from user ** namechng Show only checkins that filename changes ** ym=YYYY-MM Shown only events for the given year/month. ** ** p= and d= can appear individually or together. If either p= or d= |
| ︙ | ︙ | |||
1358 1359 1360 1361 1362 1363 1364 |
}
if( zUser ){
blob_appendf(&sql, " AND (event.user=%Q OR event.euser=%Q)",
zUser, zUser);
url_add_parameter(&url, "u", zUser);
zThisUser = zUser;
}
| | | 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 |
}
if( zUser ){
blob_appendf(&sql, " AND (event.user=%Q OR event.euser=%Q)",
zUser, zUser);
url_add_parameter(&url, "u", zUser);
zThisUser = zUser;
}
if( zSearch ){
blob_appendf(&sql,
" AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')",
zSearch, zSearch);
url_add_parameter(&url, "s", zSearch);
}
rBefore = symbolic_name_to_mtime(zBefore);
rAfter = symbolic_name_to_mtime(zAfter);
|
| ︙ | ︙ | |||
1758 1759 1760 1761 1762 1763 1764 |
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);
| | > > > > | 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 |
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("-W|--width value must be >20 or 0");
}
}else{
width = -1;
}
zOffset = find_option("offset",0,1);
iOffset = zOffset ? atoi(zOffset) : 0;
/* We should be done with options.. */
verify_all_options();
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 ){
|
| ︙ | ︙ | |||
1962 1963 1964 1965 1966 1967 1968 | */ static int statsReportType = 0; /* ** Set by stats_report_init_view() to one of the y=XXXX values ** accepted by /timeline?y=XXXX. */ | | | | | 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 |
*/
static int statsReportType = 0;
/*
** Set by stats_report_init_view() to one of the y=XXXX values
** accepted by /timeline?y=XXXX.
*/
static const char *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(){
const char *zType = PD("type","*"); /* analog to /timeline?y=... */
const char *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;
|
| ︙ | ︙ | |||
2037 2038 2039 2040 2041 2042 2043 | /* ** 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. */ | | | 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 |
/*
** 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 const char *stats_report_label_for_type(){
assert( statsReportType && "Must call stats_report_init_view() first." );
switch( statsReportType ){
case 'c':
return "checkins";
case 'e':
return "events";
case 'w':
|
| ︙ | ︙ | |||
2064 2065 2066 2067 2068 2069 2070 | ** 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. */ | | | | | 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 |
** 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(const char *zCurrentViewName,
const char *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>Types:</span> ");
|
| ︙ | ︙ | |||
2114 2115 2116 2117 2118 2119 2120 | /* ** 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. */ | | | | | | 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 |
/*
** 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 */
|
| ︙ | ︙ | |||
2209 2210 2211 2212 2213 2214 2215 |
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
++iterations;
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
| | | 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 |
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){
|
| ︙ | ︙ | |||
2294 2295 2296 2297 2298 2299 2300 |
@ <tr class='row%d(rowClass)'>
@ <td></td>
@ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
@</tr>
}
@ </tbody></table>
if(nEventTotal){
| | | 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 |
@ <tr class='row%d(rowClass)'>
@ <td></td>
@ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
@</tr>
}
@ </tbody></table>
if(nEventTotal){
const char *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");
|
| ︙ | ︙ | |||
2344 2345 2346 2347 2348 2349 2350 |
const int nCount = db_column_int(&query, 1);
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
| | | 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 |
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;
|
| ︙ | ︙ | |||
2384 2385 2386 2387 2388 2389 2390 |
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. */
| | | 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 |
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. */
static const char *const daysOfWeek[] = {
"Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"
};
stats_report_init_view();
stats_report_event_types_menu("byweekday", NULL);
blob_append(&sql,
|
| ︙ | ︙ | |||
2417 2418 2419 2420 2421 2422 2423 |
const int nCount = db_column_int(&query, 1);
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
| | | 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 |
const int nCount = db_column_int(&query, 1);
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
const int dayNum =db_column_int(&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;
|
| ︙ | ︙ | |||
2447 2448 2449 2450 2451 2452 2453 | /* ** 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. */ | | | | | 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 |
/*
** 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;
|
| ︙ | ︙ | |||
2477 2478 2479 2480 2481 2482 2483 |
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) ){
| | | 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 |
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);
|
| ︙ | ︙ | |||
2537 2538 2539 2540 2541 2542 2543 |
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
++iterations;
}
db_reset(&stWeek);
while( SQLITE_ROW == db_step(&stWeek) ){
| | | 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 |
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 );
|
| ︙ | ︙ | |||
2597 2598 2599 2600 2601 2602 2603 |
** 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 */
| | | 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 |
** 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){
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
1205 1206 1207 1208 1209 1210 1211 |
}
/* we just handle history separately here, does not get out */
if( eCmd==history ){
Stmt q;
int tagid;
| | | 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 |
}
/* we just handle history separately here, does not get out */
if( eCmd==history ){
Stmt q;
int tagid;
if( i != g.argc ){
fossil_fatal("no other parameters expected to %s!",g.argv[2]);
}
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
zTktUuid);
if( tagid==0 ){
fossil_fatal("no such ticket %h", zTktUuid);
}
|
| ︙ | ︙ | |||
1297 1298 1299 1300 1301 1302 1303 |
}
zFValue = g.argv[i++];
if( tktEncoding == tktFossilize ){
zFValue=mprintf("%s",zFValue);
defossilize(zFValue);
}
append = (zFName[0] == '+');
| | | | | | | | 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 |
}
zFValue = g.argv[i++];
if( tktEncoding == tktFossilize ){
zFValue=mprintf("%s",zFValue);
defossilize(zFValue);
}
append = (zFName[0] == '+');
if( append ){
zFName++;
}
j = fieldId(zFName);
if( j == -1 ){
fossil_fatal("unknown field name '%s'!",zFName);
}else{
if( append ){
aField[j].zAppend = zFValue;
}else{
aField[j].zValue = zFValue;
}
}
}
/* now add the needed artifacts to the repository */
blob_zero(&tktchng);
/* add the time to the ticket manifest */
blob_appendf(&tktchng, "D %s\n", zDate);
/* append defined elements */
for(i=0; i<nField; i++){
char *zValue = 0;
char *zPfx;
if( aField[i].zAppend && aField[i].zAppend[0] ){
zPfx = " +";
zValue = aField[i].zAppend;
}else if( aField[i].zValue && aField[i].zValue[0] ){
zPfx = " ";
zValue = aField[i].zValue;
}else{
continue;
}
if( memcmp(aField[i].zName, "private_", 8)==0 ){
zValue = db_conceal(zValue, strlen(zValue));
blob_appendf(&tktchng, "J%s%s %s\n", zPfx, aField[i].zName, zValue);
}else{
blob_appendf(&tktchng, "J%s%s %#F\n", zPfx,
|
| ︙ | ︙ |
Changes to src/unicode.c.
| ︙ | ︙ | |||
206 207 208 209 210 211 212 |
iLo = iTest+1;
}else{
iHi = iTest-1;
}
}
assert( key>=aDia[iRes] );
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
| < > | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
iLo = iTest+1;
}else{
iHi = iTest-1;
}
}
assert( key>=aDia[iRes] );
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
}
/*
** Return true if the argument interpreted as a unicode codepoint
** is a diacritical modifier character.
*/
int unicode_is_diacritic(int c){
|
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
60 61 62 63 64 65 66 | } /* ** COMMAND: update ** ** Usage: %fossil update ?OPTIONS? ?VERSION? ?FILES...? ** | | | | | | | | > | | | | > > > > > | | | | | | 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 | } /* ** COMMAND: update ** ** Usage: %fossil update ?OPTIONS? ?VERSION? ?FILES...? ** ** Change the version of the current checkout to VERSION. Any ** uncommitted changes are retained and applied to the new checkout. ** ** The VERSION argument can be a specific version or tag or branch ** name. If the VERSION argument is omitted, then the leaf of the ** subtree that begins at the current version is used, if there is ** only a single leaf. VERSION can also be "current" to select the ** leaf of the current version or "latest" to select the most recent ** check-in. ** ** If one or more FILES are listed after the VERSION then only the ** named files are candidates to be updated, and any updates to them ** will be treated as edits to the current version. Using a directory ** name for one of the FILES arguments is the same as using every ** subdirectory and file beneath that directory. ** ** If FILES is omitted, all files in the current checkout are subject ** to being updated and the version of the current checkout is changed ** to VERSION. Any uncommitted changes are retained and applied to the ** new checkout. ** ** The -n or --dry-run option causes this command to do a "dry run". ** It prints out what would have happened but does not actually make ** any changes to the current checkout or the repository. ** ** The -v or --verbose option prints status information about ** unchanged files in addition to those file that actually do change. ** ** Options: ** --case-sensitive <BOOL> override case-sensitive setting ** --debug print debug information on stdout ** --latest acceptable in place of VERSION, update to latest version ** --force-missing force update if missing content after sync ** -n|--dry-run If given, display instead of run actions |
| ︙ | ︙ | |||
137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */
}
verboseFlag = find_option("verbose","v",0)!=0;
forceMissingFlag = find_option("force-missing",0,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 ){
if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag,
db_get_int("autosync-tries", 1)) ){
fossil_fatal("Cannot proceed with update");
| > > > > | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */
}
verboseFlag = find_option("verbose","v",0)!=0;
forceMissingFlag = find_option("force-missing",0,0)!=0;
debugFlag = find_option("debug",0,0)!=0;
setmtimeFlag = find_option("setmtime",0,0)!=0;
capture_case_sensitive_option();
/* We should be done with options.. */
verify_all_options();
db_must_be_within_tree();
vid = db_lget_int("checkout", 0);
user_select();
if( !dryRunFlag && !internalUpdate ){
if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag,
db_get_int("autosync-tries", 1)) ){
fossil_fatal("Cannot proceed with update");
|
| ︙ | ︙ | |||
259 260 261 262 263 264 265 |
" FROM vfile WHERE vid=%d",
vid
);
/* Compute file name changes on V->T. Record name changes in files that
** have changed locally.
*/
| > | | | | | | | | | | | > | 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 |
" FROM vfile WHERE vid=%d",
vid
);
/* Compute file name changes on V->T. Record name changes in files that
** have changed locally.
*/
if( vid ){
find_filename_changes(vid, tid, 1, &nChng, &aChng, debugFlag ? "V->T": 0);
if( nChng ){
for(i=0; i<nChng; i++){
db_multi_exec(
"UPDATE fv"
" SET fnt=(SELECT name FROM filename WHERE fnid=%d)"
" WHERE fn=(SELECT name FROM filename WHERE fnid=%d) AND chnged",
aChng[i*2+1], aChng[i*2]
);
}
fossil_free(aChng);
}
}
/* Add files found in the target version T but missing from the current
** version V.
*/
db_multi_exec(
"INSERT OR IGNORE INTO fv(fn,fnt,idv,idt,ridv,ridt,isexe,chnged)"
|
| ︙ | ︙ |
Changes to src/utf8.c.
| ︙ | ︙ | |||
125 126 127 128 129 130 131 |
}
WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, zUtf, nByte, 0, 0);
pUtf = qUtf = zUtf;
while( *pUtf ) {
if( *pUtf == (char)0xef ){
wchar_t c = ((pUtf[1]&0x3f)<<6)|(pUtf[2]&0x3f);
/* Only really convert it when the resulting char is in range. */
| | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
}
WideCharToMultiByte(CP_UTF8, 0, zFilename, -1, zUtf, nByte, 0, 0);
pUtf = qUtf = zUtf;
while( *pUtf ) {
if( *pUtf == (char)0xef ){
wchar_t c = ((pUtf[1]&0x3f)<<6)|(pUtf[2]&0x3f);
/* Only really convert it when the resulting char is in range. */
if( c && ((c < ' ') || wcschr(L"\"*:<>?|", c)) ){
*qUtf++ = c; pUtf+=3; continue;
}
}
*qUtf++ = *pUtf++;
}
*qUtf = 0;
return zUtf;
|
| ︙ | ︙ | |||
239 240 241 242 243 244 245 |
/*
** In the remainder of the path, translate invalid characters to
** characters in the Unicode private use area. This is what makes
** Win32 fossil.exe work well in a Cygwin environment even when a
** filename contains characters which are invalid for Win32.
*/
while( *wUnicode != '\0' ){
| | | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
/*
** In the remainder of the path, translate invalid characters to
** characters in the Unicode private use area. This is what makes
** Win32 fossil.exe work well in a Cygwin environment even when a
** filename contains characters which are invalid for Win32.
*/
while( *wUnicode != '\0' ){
if( (*wUnicode < ' ') || wcschr(L"\"*:<>?|", *wUnicode) ){
*wUnicode |= 0xF000;
}else if( *wUnicode == '/' ){
*wUnicode = '\\';
}
++wUnicode;
}
return zUnicode;
|
| ︙ | ︙ |
Changes to src/util.c.
| ︙ | ︙ | |||
293 294 295 296 297 298 299 |
** Returns true (non-0) if the given timer ID (as returned from
** fossil_timer_start() is currently active.
*/
int fossil_timer_is_active( int timerId ){
if(timerId<1 || timerId>FOSSIL_TIMER_COUNT){
return 0;
}else{
| | | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
** Returns true (non-0) if the given timer ID (as returned from
** fossil_timer_start() is currently active.
*/
int fossil_timer_is_active( int timerId ){
if(timerId<1 || timerId>FOSSIL_TIMER_COUNT){
return 0;
}else{
const int 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
|
| ︙ | ︙ | |||
315 316 317 318 319 320 321 | #endif } /* ** Returns TRUE if zSym is exactly UUID_SIZE bytes long and contains ** only lower-case ASCII hexadecimal values. */ | | | 315 316 317 318 319 320 321 322 323 324 325 326 |
#endif
}
/*
** Returns TRUE if zSym is exactly UUID_SIZE bytes long and contains
** only lower-case ASCII hexadecimal values.
*/
int fossil_is_uuid(const char *zSym){
return zSym
&& (UUID_SIZE==strlen(zSym))
&& validate16(zSym, UUID_SIZE);
}
|
Changes to src/wiki.c.
| ︙ | ︙ | |||
858 859 860 861 862 863 864 |
** WEBPAGE: wfind
**
** URL: /wfind?title=TITLE
** List all wiki pages whose titles contain the search text
*/
void wfind_page(void){
Stmt q;
| | | 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 |
** WEBPAGE: wfind
**
** URL: /wfind?title=TITLE
** List all wiki pages whose titles contain the search text
*/
void wfind_page(void){
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%%'"
|
| ︙ | ︙ | |||
958 959 960 961 962 963 964 | ** ** The content of the new page is given by the blob pContent. ** ** zMimeType specifies the N-card for the wiki page. If it is 0, ** empty, or "text/x-fossil-wiki" (the default format) then it is ** ignored. */ | | | | | 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 |
**
** The content of the new page is given by the blob pContent.
**
** zMimeType specifies the N-card for the wiki page. If it is 0,
** empty, or "text/x-fossil-wiki" (the default format) then it is
** ignored.
*/
int wiki_cmd_commit(const char *zPageName, int isNew, Blob *pContent,
const char *zMimeType){
Blob wiki; /* Wiki page content */
Blob cksum; /* wiki checksum */
int rid; /* artifact ID of parent page */
char *zDate; /* timestamp */
char *zUuid; /* uuid for rid */
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( rid==0 && !isNew ){
|
| ︙ | ︙ | |||
1056 1057 1058 1059 1060 1061 1062 |
}
n = strlen(g.argv[2]);
if( n==0 ){
goto wiki_cmd_usage;
}
if( strncmp(g.argv[2],"export",n)==0 ){
| | | | 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 |
}
n = strlen(g.argv[2]);
if( n==0 ){
goto wiki_cmd_usage;
}
if( strncmp(g.argv[2],"export",n)==0 ){
const char *zPageName; /* Name of the wiki page to export */
const char *zFile; /* Name of the output file (0=stdout) */
int rid; /* Artifact ID of the wiki page */
int i; /* Loop counter */
char *zBody = 0; /* Wiki page content */
Blob body; /* Wiki page content */
Manifest *pWiki = 0; /* Parsed wiki page content */
if( (g.argc!=4) && (g.argc!=5) ){
usage("export PAGENAME ?FILE?");
|
| ︙ | ︙ | |||
1089 1090 1091 1092 1093 1094 1095 |
blob_append(&body, "\n", 1);
blob_write_to_file(&body, zFile);
blob_reset(&body);
manifest_destroy(pWiki);
return;
}else if( strncmp(g.argv[2],"commit",n)==0
|| strncmp(g.argv[2],"create",n)==0 ){
| | | | 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 |
blob_append(&body, "\n", 1);
blob_write_to_file(&body, zFile);
blob_reset(&body);
manifest_destroy(pWiki);
return;
}else if( strncmp(g.argv[2],"commit",n)==0
|| strncmp(g.argv[2],"create",n)==0 ){
const char *zPageName; /* page name */
Blob content; /* Input content */
int rid;
Manifest *pWiki = 0; /* Parsed wiki page content */
const char *zMimeType = find_option("mimetype", "M", 1);
if( g.argc!=4 && g.argc!=5 ){
usage("commit|create PAGENAME ?FILE? [-mimetype TEXT-FORMAT]");
}
zPageName = g.argv[3];
if( g.argc==4 ){
blob_read_from_channel(&content, stdin, -1);
}else{
|
| ︙ | ︙ |
Changes to src/winhttp.c.
| ︙ | ︙ | |||
680 681 682 683 684 685 686 |
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 ){
| | > > > > > | 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
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("too many arguments for create method.");
}
/* Process service creation specific options. */
if( !zDisplay ){
zDisplay = zSvcName;
}
/* Per MSDN, the password parameter cannot be NULL. Must use empty
** string instead (i.e. in the call to CreateServiceW). */
if( !zPassword ){
zPassword = "";
}
if( zStart ){
if( strncmp(zStart, "auto", strlen(zStart))==0 ){
dwStartType = SERVICE_AUTO_START;
}else if( strncmp(zStart, "manual", strlen(zStart))==0 ){
dwStartType = SERVICE_DEMAND_START;
}else{
|
| ︙ | ︙ | |||
734 735 736 737 738 739 740 |
SERVICE_WIN32_OWN_PROCESS, /* Service type */
dwStartType, /* Start type */
SERVICE_ERROR_NORMAL, /* Error control */
fossil_utf8_to_unicode(blob_str(&binPath)), /* Binary path */
NULL, /* Load ordering group */
NULL, /* Tag value */
NULL, /* Service dependencies */
| | | | 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 |
SERVICE_WIN32_OWN_PROCESS, /* Service type */
dwStartType, /* Start type */
SERVICE_ERROR_NORMAL, /* Error control */
fossil_utf8_to_unicode(blob_str(&binPath)), /* Binary path */
NULL, /* Load ordering group */
NULL, /* Tag value */
NULL, /* Service dependencies */
zUsername ? fossil_utf8_to_unicode(zUsername) : 0, /* Account */
fossil_utf8_to_unicode(zPassword) /* Account password */
);
if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
/* Set the service description. */
ChangeServiceConfig2W(hSvc, SERVICE_CONFIG_DESCRIPTION, &svcDescr);
fossil_print("Service '%s' successfully created.\n", zSvcName);
CloseServiceHandle(hSvc);
CloseServiceHandle(hScm);
}else
if( strncmp(zMethod, "delete", n)==0 ){
SC_HANDLE hScm;
SC_HANDLE hSvc;
SERVICE_STATUS sstat;
char *zErrFmt = "unable to delete service '%s': %s";
verify_all_options();
if( g.argc==4 ){
zSvcName = g.argv[3];
}else if( g.argc>4 ){
fossil_fatal("too many arguments for delete method.");
}
hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName),
SERVICE_ALL_ACCESS);
if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
QueryServiceStatus(hSvc, &sstat);
|
| ︙ | ︙ | |||
823 824 825 826 827 828 829 |
};
const char *zSvcState = "";
verify_all_options();
if( g.argc==4 ){
zSvcName = g.argv[3];
}else if( g.argc>4 ){
| | | 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 |
};
const char *zSvcState = "";
verify_all_options();
if( g.argc==4 ){
zSvcName = g.argv[3];
}else if( g.argc>4 ){
fossil_fatal("too many arguments for show method.");
}
hScm = OpenSCManagerW(NULL, NULL, GENERIC_READ);
if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName), GENERIC_READ);
if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
/* Get the service configuration */
bStatus = QueryServiceConfigW(hSvc, NULL, 0, &nRequired);
|
| ︙ | ︙ | |||
905 906 907 908 909 910 911 |
SERVICE_STATUS sstat;
char *zErrFmt = "unable to start service '%s': %s";
verify_all_options();
if( g.argc==4 ){
zSvcName = g.argv[3];
}else if( g.argc>4 ){
| | | 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 |
SERVICE_STATUS sstat;
char *zErrFmt = "unable to start service '%s': %s";
verify_all_options();
if( g.argc==4 ){
zSvcName = g.argv[3];
}else if( g.argc>4 ){
fossil_fatal("too many arguments for start method.");
}
hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName),
SERVICE_ALL_ACCESS);
if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
QueryServiceStatus(hSvc, &sstat);
|
| ︙ | ︙ | |||
942 943 944 945 946 947 948 |
SERVICE_STATUS sstat;
char *zErrFmt = "unable to stop service '%s': %s";
verify_all_options();
if( g.argc==4 ){
zSvcName = g.argv[3];
}else if( g.argc>4 ){
| | | 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 |
SERVICE_STATUS sstat;
char *zErrFmt = "unable to stop service '%s': %s";
verify_all_options();
if( g.argc==4 ){
zSvcName = g.argv[3];
}else if( g.argc>4 ){
fossil_fatal("too many arguments for stop method.");
}
hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName),
SERVICE_ALL_ACCESS);
if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
QueryServiceStatus(hSvc, &sstat);
|
| ︙ | ︙ |
Changes to src/wysiwyg.c.
| ︙ | ︙ | |||
249 250 251 252 253 254 255 |
@ 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()){
| > > > > | > > > > > > > > | 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 |
@ 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()){
@ try {
@ // First, try the W3C draft standard way, which has
@ // been working on all non-IE browsers for a while.
@ // It is also supported by IE11 and higher.
@ document.execCommand("styleWithCSS", false, false);
@ } catch (e) {
@ try {
@ // For IE9 or IE10, this should work.
@ document.execCommand("useCSS", 0, true);
@ } catch (e) {
@ // Ok, that apparently did not work, do nothing.
@ }
@ }
@ 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. */
|
| ︙ | ︙ |
Changes to src/zip.c.
| ︙ | ︙ | |||
391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
*/
void baseline_zip_cmd(void){
int rid;
Blob zip;
const char *zName;
zName = find_option("name", 0, 1);
db_find_and_open_repository(0, 0);
if( g.argc!=4 ){
usage("VERSION OUTPUTFILE");
}
rid = name_to_typed_rid(g.argv[2],"ci");
if( zName==0 ){
zName = db_text("default-name",
"SELECT replace(%Q,' ','_') "
| > > > > | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
*/
void baseline_zip_cmd(void){
int rid;
Blob zip;
const char *zName;
zName = find_option("name", 0, 1);
db_find_and_open_repository(0, 0);
/* We should be done with options.. */
verify_all_options();
if( g.argc!=4 ){
usage("VERSION OUTPUTFILE");
}
rid = name_to_typed_rid(g.argv[2],"ci");
if( zName==0 ){
zName = db_text("default-name",
"SELECT replace(%Q,' ','_') "
|
| ︙ | ︙ | |||
419 420 421 422 423 424 425 | ** URL: /zip/RID.zip ** ** Generate a ZIP archive for the baseline. ** Return that ZIP archive as the HTTP reply content. ** ** Optional URL Parameters: ** | | | > > | > > > > > > > | | | | > | 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 |
** URL: /zip/RID.zip
**
** Generate a ZIP archive for the baseline.
** Return that ZIP archive as the HTTP reply content.
**
** Optional URL Parameters:
**
** - name=NAME[.zip] is the name of the output file. Defaults to
** something project/version-specific. The base part of the
** name, up to the last dot, is used as the top-most directory
** name in the output file.
**
** - uuid=the version to zip (may be a tag/branch name).
** Defaults to "trunk".
**
*/
void baseline_zip_page(void){
int rid;
char *zName, *zRid;
int nName, nRid;
Blob zip;
char *zKey;
login_check_credentials();
if( !g.perm.Zip ){ login_needed(); return; }
load_control();
zName = mprintf("%s", PD("name",""));
nName = strlen(zName);
zRid = mprintf("%s", PD("uuid","trunk"));
nRid = strlen(zRid);
if( nName>4 && fossil_strcmp(&zName[nName-4], ".zip")==0 ){
/* Special case: Remove the ".zip" suffix. */
nName -= 4;
zName[nName] = 0;
}else{
/* If the file suffix is not ".zip" then just remove the
** suffix up to and including the last "." */
for(nName=strlen(zName)-1; nName>5; nName--){
if( zName[nName]=='.' ){
zName[nName] = 0;
break;
}
}
}
rid = name_to_typed_rid(nRid?zRid:zName,"ci");
if( rid==0 ){
@ Not found
return;
}
|
| ︙ | ︙ |
Changes to test/comment.test.
| ︙ | ︙ | |||
225 226 227 228 229 230 231 |
fossil test-comment-format --width 60 --legacy --wordbreak "*TEST* " "one two three four five six seven eight nine ten eleven twelve"
test comment-42 {$RESULT eq "*TEST* one two three four five six seven eight nine ten\n eleven twelve\n(2 lines output)"}
###############################################################################
set orig "xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\\nxxxxxxx."
| | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
fossil test-comment-format --width 60 --legacy --wordbreak "*TEST* " "one two three four five six seven eight nine ten eleven twelve"
test comment-42 {$RESULT eq "*TEST* one two three four five six seven eight nine ten\n eleven twelve\n(2 lines output)"}
###############################################################################
set orig "xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\\nxxxxxxx."
fossil test-comment-format --width 73 --decode --origbreak "" $orig
test comment-43 {$RESULT eq "xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\nxxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 73 --decode --origbreak "" $orig $orig
test comment-44 {$RESULT eq "xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\nxxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 73 --decode --origbreak "" "00:00:00 \[0000000000\] *CURRENT* $orig" $orig
test comment-45 {$RESULT eq "00:00:00 \[0000000000\] *CURRENT* \nxxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\nxxxxxxx.\n(6 lines output)"}
###############################################################################
fossil test-comment-format --width 82 --indent 9 --decode --origbreak " " $orig
test comment-46 {$RESULT eq " xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 82 --indent 9 --decode --origbreak " " $orig $orig
test comment-47 {$RESULT eq " xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 82 --indent 9 --decode --origbreak "00:00:00 " "\[0000000000\] *CURRENT* $orig" $orig
test comment-48 {$RESULT eq "00:00:00 \[0000000000\] *CURRENT* \n xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(6 lines output)"}
###############################################################################
fossil test-comment-format --width 72 --decode --trimspace --origbreak "" $orig
test comment-49 {$RESULT eq "xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\nxxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 72 --decode --trimspace --origbreak "" $orig $orig
test comment-50 {$RESULT eq "xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\nxxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 72 --decode --trimspace --origbreak "" "00:00:00 \[0000000000\] *CURRENT* $orig" $orig
test comment-51 {$RESULT eq "00:00:00 \[0000000000\] *CURRENT* \nxxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\nxxxxxxx.\n(6 lines output)"}
###############################################################################
fossil test-comment-format --width 81 --indent 9 --decode --trimspace --origbreak " " $orig
test comment-52 {$RESULT eq " xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 81 --indent 9 --decode --trimspace --origbreak " " $orig $orig
test comment-53 {$RESULT eq " xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 81 --indent 9 --decode --trimspace --origbreak "00:00:00 " "\[0000000000\] *CURRENT* $orig" $orig
test comment-54 {$RESULT eq "00:00:00 \[0000000000\] *CURRENT* \n xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(6 lines output)"}
###############################################################################
fossil test-comment-format --width 72 --decode --trimcrlf --origbreak "" $orig
test comment-55 {$RESULT eq "xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\nxxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 72 --decode --trimcrlf --origbreak "" $orig $orig
test comment-56 {$RESULT eq "xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\nxxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 72 --decode --trimcrlf --origbreak "" "00:00:00 \[0000000000\] *CURRENT* $orig" $orig
test comment-57 {$RESULT eq "00:00:00 \[0000000000\] *CURRENT* \nxxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\nxxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\nxxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\nxxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\nxxxxxxx.\n(6 lines output)"}
###############################################################################
fossil test-comment-format --width 81 --indent 9 --decode --trimcrlf --origbreak " " $orig
test comment-58 {$RESULT eq " xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 81 --indent 9 --decode --trimcrlf --origbreak " " $orig $orig
test comment-59 {$RESULT eq " xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(5 lines output)"}
###############################################################################
fossil test-comment-format --width 81 --indent 9 --decode --trimcrlf --origbreak "00:00:00 " "\[0000000000\] *CURRENT* $orig" $orig
test comment-60 {$RESULT eq "00:00:00 \[0000000000\] *CURRENT* \n xxxx xx xxxxxxx xxxx xxxxxx xxxxxxx, xxxxxxx, x xxxx xxxxxx xx xxxx xxxx\n xxxxxxx xxxxx xxxx xxxx xx xxxxxxx xxxxxxx (xxxxxx xxxxxxxxx x xxxxx).\n xxx'x xxx xxx xx xxxxx xxxx xxx xxx --xxxxxxxxxxx xxxxxx xx xx xxxx. x\n xxxxx x xxxxxx xxxx xxxx xxxx xxxx xxxx x xxxxx xx xxx x xxxxxxxx\n xxxxxxx.\n(6 lines output)"}
|
Changes to test/release-checklist.wiki.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | [./graph-test-1.wiki] document and verify that all graphs are rendered correctly. <li><p> Click on each of the links in in the [./diff-test-1.wiki] document and verify that all diffs are rendered correctly. | < > > > > > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | [./graph-test-1.wiki] document and verify that all graphs are rendered correctly. <li><p> Click on each of the links in in the [./diff-test-1.wiki] document and verify that all diffs are rendered correctly. <li><p> Click on the following link to verify that it works: [./test-page%2b%2b.wiki | ./test-page++.wiki] (NB: Many web servers automatically block or rewrite URLs that contain "+" characters, even when those "+" characters are encoded as "%2B". On such web servers, the URL above will not work. This test is only guaranteed to work when running "fossil ui".) <li><p> Verify correct name-change tracking behavior (no net changes) for: <blockquote><b> fossil test-name-changes --debug b120bc8b262ac 374920b20944b </b></blockquote> |
| ︙ | ︙ |
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 | 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=-DNDEBUG=1 -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 -DSQLITE_WIN32_NO_ANSI # 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 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen |
| ︙ | ︙ |
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 | 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 = -DNDEBUG=1 -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 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c cache_.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 fusefs_.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 loadctrl_.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)\cache$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)\fusefs$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)\loadctrl$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 |
| ︙ | ︙ |
Changes to win/Makefile.mingw.
| ︙ | ︙ | |||
90 91 92 93 94 95 96 | 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. # | | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 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.1i/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1i #### 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 |
| ︙ | ︙ | |||
1763 1764 1765 1766 1767 1768 1769 | $(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 | > | > | 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 |
$(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 = -DNDEBUG=1 \
-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 \
-DSQLITE_WIN32_NO_ANSI \
-D_HAVE__MINGW_H \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -Dmain=sqlite3_shell \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
|
| ︙ | ︙ |
Changes to win/Makefile.mingw.mistachkin.
| ︙ | ︙ | |||
90 91 92 93 94 95 96 | 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. # | | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 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.1i/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1i #### 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 |
| ︙ | ︙ | |||
1763 1764 1765 1766 1767 1768 1769 | $(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 | > | > | 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 |
$(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 = -DNDEBUG=1 \
-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 \
-DSQLITE_WIN32_NO_ANSI \
-D_HAVE__MINGW_H \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -Dmain=sqlite3_shell \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
|
| ︙ | ︙ |
Changes to win/Makefile.msc.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 | # Uncomment to enable TH1 hooks # FOSSIL_ENABLE_TH1_HOOKS = 1 # Uncomment to enable Tcl support # FOSSIL_ENABLE_TCL = 1 !ifdef FOSSIL_ENABLE_SSL | | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # Uncomment to enable TH1 hooks # FOSSIL_ENABLE_TH1_HOOKS = 1 # Uncomment to enable Tcl support # FOSSIL_ENABLE_TCL = 1 !ifdef FOSSIL_ENABLE_SSL SSLINCDIR = $(B)\compat\openssl-1.0.1i\include SSLLIBDIR = $(B)\compat\openssl-1.0.1i\out32 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib !endif !ifdef FOSSIL_ENABLE_TCL TCLDIR = $(B)\compat\tcl-8.6 TCLSRCDIR = $(TCLDIR) TCLINCDIR = $(TCLSRCDIR)\generic |
| ︙ | ︙ | |||
97 98 99 100 101 102 103 | RCC = $(RCC) /DFOSSIL_ENABLE_TCL_STUBS=1 TCC = $(TCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 RCC = $(RCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 TCC = $(TCC) /DUSE_TCL_STUBS=1 RCC = $(RCC) /DUSE_TCL_STUBS=1 !endif | > | | > | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
RCC = $(RCC) /DFOSSIL_ENABLE_TCL_STUBS=1
TCC = $(TCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1
RCC = $(RCC) /DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1
TCC = $(TCC) /DUSE_TCL_STUBS=1
RCC = $(RCC) /DUSE_TCL_STUBS=1
!endif
SQLITE_OPTIONS = /DNDEBUG=1 \
/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 \
/DSQLITE_WIN32_NO_ANSI
SHELL_OPTIONS = /Dmain=sqlite3_shell \
/DSQLITE_OMIT_LOAD_EXTENSION=1 \
/DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
/DSQLITE_SHELL_DBNAME_PROC=fossil_open \
/Daccess=file_access \
/Dsystem=fossil_system \
|
| ︙ | ︙ |
Changes to win/include/dirent.h.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL TONI RONKKO 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. * | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < < < < < < > > > > > | | | 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 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL TONI RONKKO 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. * * $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $ */ #ifndef DIRENT_H #define DIRENT_H /* * Define architecture flags so we don't need to include windows.h. * Avoiding windows.h makes it simpler to use windows sockets in conjunction * with dirent.h. */ #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) # define _X86_ #endif #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64) #define _AMD64_ #endif #include <stdio.h> #include <stdarg.h> #include <windef.h> #include <winbase.h> |
| ︙ | ︙ | |||
211 212 213 214 215 216 217 | #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) /* Return the exact length of d_namlen without zero terminator */ #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) /* Return number of bytes needed to store d_namlen */ | | | | 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 |
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
/* Return the exact length of d_namlen without zero terminator */
#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
/* Return number of bytes needed to store d_namlen */
#define _D_ALLOC_NAMLEN(p) (PATH_MAX)
#ifdef __cplusplus
extern "C" {
#endif
/* Wide-character version */
struct _wdirent {
long d_ino; /* Always zero */
unsigned short d_reclen; /* Structure size */
size_t d_namlen; /* Length of name without \0 */
int d_type; /* File type */
wchar_t d_name[PATH_MAX]; /* File name */
};
typedef struct _wdirent _wdirent;
struct _WDIR {
struct _wdirent ent; /* Current directory entry */
WIN32_FIND_DATAW data; /* Private file data */
int cached; /* True if data is valid */
|
| ︙ | ︙ | |||
259 260 261 262 263 264 265 |
/* Multi-byte character versions */
struct dirent {
long d_ino; /* Always zero */
unsigned short d_reclen; /* Structure size */
size_t d_namlen; /* Length of name without \0 */
int d_type; /* File type */
| | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
/* Multi-byte character versions */
struct dirent {
long d_ino; /* Always zero */
unsigned short d_reclen; /* Structure size */
size_t d_namlen; /* Length of name without \0 */
int d_type; /* File type */
char d_name[PATH_MAX]; /* File name */
};
typedef struct dirent dirent;
struct DIR {
struct dirent ent;
struct _WDIR *wdirp;
};
|
| ︙ | ︙ | |||
421 422 423 424 425 426 427 |
/*
* Copy file name as wide-character string. If the file name is too
* long to fit in to the destination buffer, then truncate file name
* to PATH_MAX characters and zero-terminate the buffer.
*/
n = 0;
| | | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
/*
* Copy file name as wide-character string. If the file name is too
* long to fit in to the destination buffer, then truncate file name
* to PATH_MAX characters and zero-terminate the buffer.
*/
n = 0;
while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) {
entp->d_name[n] = datap->cFileName[n];
n++;
}
dirp->ent.d_name[n] = 0;
/* Length of file name excluding zero terminator */
entp->d_namlen = n;
|
| ︙ | ︙ | |||
590 591 592 593 594 595 596 |
dirent_set_errno (ENOENT);
return NULL;
}
/* Allocate memory for DIR structure */
dirp = (DIR*) malloc (sizeof (struct DIR));
if (dirp) {
| | | < | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 |
dirent_set_errno (ENOENT);
return NULL;
}
/* Allocate memory for DIR structure */
dirp = (DIR*) malloc (sizeof (struct DIR));
if (dirp) {
wchar_t wname[PATH_MAX];
size_t n;
/* Convert directory name to wide-character string */
error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX);
if (!error) {
/* Open directory stream using wide-character name */
dirp->wdirp = _wopendir (wname);
if (dirp->wdirp) {
/* Directory stream opened */
error = 0;
|
| ︙ | ︙ | |||
660 661 662 663 664 665 666 |
datap = dirent_next (dirp->wdirp);
if (datap) {
size_t n;
int error;
/* Attempt to convert file name to multi-byte string */
error = dirent_wcstombs_s(
| | | | < | 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 |
datap = dirent_next (dirp->wdirp);
if (datap) {
size_t n;
int error;
/* Attempt to convert file name to multi-byte string */
error = dirent_wcstombs_s(
&n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);
/*
* If the file name cannot be represented by a multi-byte string,
* then attempt to use old 8+3 file name. This allows traditional
* Unix-code to access some file names despite of unicode
* characters, although file names may seem unfamiliar to the user.
*
* Be ware that the code below cannot come up with a short file
* name unless the file system provides one. At least
* VirtualBox shared folders fail to do this.
*/
if (error && datap->cAlternateFileName[0] != '\0') {
error = dirent_wcstombs_s(
&n, dirp->ent.d_name, PATH_MAX,
datap->cAlternateFileName, PATH_MAX);
}
if (!error) {
DWORD attr;
/* Initialize directory entry for return */
entp = &dirp->ent;
|
| ︙ | ︙ | |||
785 786 787 788 789 790 791 |
error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
#else
/* Older Visual Studio or non-Microsoft compiler */
size_t n;
| | | | | > > > | 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 |
error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
#else
/* Older Visual Studio or non-Microsoft compiler */
size_t n;
/* Convert to wide-character string (or count characters) */
n = mbstowcs (wcstr, mbstr, sizeInWords);
if (!wcstr || n < count) {
/* Zero-terminate output buffer */
if (wcstr && sizeInWords) {
if (n >= sizeInWords) {
n = sizeInWords - 1;
}
wcstr[n] = 0;
}
/* Length of resuting multi-byte string WITH zero terminator */
if (pReturnValue) {
*pReturnValue = n + 1;
}
|
| ︙ | ︙ | |||
819 820 821 822 823 824 825 |
}
/* Convert wide-character string to multi-byte string */
static int
dirent_wcstombs_s(
size_t *pReturnValue,
char *mbstr,
| | | | | | > > > | 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 |
}
/* Convert wide-character string to multi-byte string */
static int
dirent_wcstombs_s(
size_t *pReturnValue,
char *mbstr,
size_t sizeInBytes, /* max size of mbstr */
const wchar_t *wcstr,
size_t count)
{
int error;
#if defined(_MSC_VER) && _MSC_VER >= 1400
/* Microsoft Visual Studio 2005 or later */
error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
#else
/* Older Visual Studio or non-Microsoft compiler */
size_t n;
/* Convert to multi-byte string (or count the number of bytes needed) */
n = wcstombs (mbstr, wcstr, sizeInBytes);
if (!mbstr || n < count) {
/* Zero-terminate output buffer */
if (mbstr && sizeInBytes) {
if (n >= sizeInBytes) {
n = sizeInBytes - 1;
}
mbstr[n] = '\0';
}
/* Lenght of resulting multi-bytes string WITH zero-terminator */
if (pReturnValue) {
*pReturnValue = n + 1;
}
|
| ︙ | ︙ | |||
869 870 871 872 873 874 875 |
}
/* Set errno variable */
static void
dirent_set_errno(
int error)
{
| | | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 |
}
/* Set errno variable */
static void
dirent_set_errno(
int error)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
/* Microsoft Visual Studio 2005 and later */
_set_errno (error);
#else
/* Non-Microsoft compiler or older Microsoft compiler */
|
| ︙ | ︙ |
Changes to www/quotes.wiki.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | <li value=7> Fossil mesmerizes me with simplicity especially after I struggled to get a bug-tracking system to work with mercurial. <blockquote> <i>rawjeev at [http://stackoverflow.com/questions/156322/what-do-people-think-of-the-fossil-dvcs]</i> </blockquote> <li>Fossil is awesome!!! I have never seen an app like that before, such simplicity and flexibility!!! <blockquote> <i>zengr at [http://stackoverflow.com/questions/138621/best-version-control-for-lone-developer]</i> </blockquote> </ol> <h2>On Git Versus Fossil</h2> <ol> | > > > > > > > > > > | | 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 | <li value=7> Fossil mesmerizes me with simplicity especially after I struggled to get a bug-tracking system to work with mercurial. <blockquote> <i>rawjeev at [http://stackoverflow.com/questions/156322/what-do-people-think-of-the-fossil-dvcs]</i> </blockquote> <li>Fossil is the best thing to happen to my development workflow this year, as I am pretty sure that using Git has resulted in the premature death of too many of my brain cells. I'm glad to be able to replace Git in every place that I possibly can with Fossil. <blockquote> <i>Joe Prostko at [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg16716.html] </blockquote> <li>Fossil is awesome!!! I have never seen an app like that before, such simplicity and flexibility!!! <blockquote> <i>zengr at [http://stackoverflow.com/questions/138621/best-version-control-for-lone-developer]</i> </blockquote> </ol> <h2>On Git Versus Fossil</h2> <ol> <li value=10> Just want to say thanks for fossil making my life easier.... Also <nowiki>[for]</nowiki> not having a misanthropic command line interface. <blockquote> <i>Joshua Paine at [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg02736.html]</i> </blockquote> |
| ︙ | ︙ |
Changes to www/sync.wiki.
| ︙ | ︙ | |||
157 158 159 160 161 162 163 | checks out, then the client is granted all privileges of the specified user.</p> <p>Privileges are cumulative. There can be multiple successful login cards. The session privileges are the bit-wise OR of the privileges of each individual login.</p> | | | | > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | checks out, then the client is granted all privileges of the specified user.</p> <p>Privileges are cumulative. There can be multiple successful login cards. The session privileges are the bit-wise OR of the privileges of each individual login.</p> <h3>3.3 File and Compressed File Cards</h3> <p>Artifacts are transferred using either "file" cards, or "cfile" cards. (The name "file" card comes from the fact that most artifacts correspond to files, and "cfile" is just a compressed file.) </p> <h4>3.3.1 File Cards</h4> <p>For sync protocols, artifacts are transferred using "file" cards. File cards come in two different formats depending on whether the artifact is sent directly or as a delta from some other artifact.</p> <blockquote> <b>file</b> <i>artifact-id size</i> <b>\n</b> <i>content</i><br> <b>file</b> <i>artifact-id delta-artifact-id size</i> <b>\n</b> <i>content</i> </blockquote> <p>File cards are different from all other cards in that they followed by in-line "payload" data. The content of the artifact or the artifact delta consists of the first <i>size</i> bytes of the x-fossil content that immediately follow the newline that terminates the file card. Only file and cfile cards have this characteristic. </p> <p>The first argument of a file card is the ID of the artifact that is being transferred. The artifact ID is the lower-case hexadecimal representation of the SHA1 hash of the artifact. The last argument of the file card is the number of bytes of payload that immediately follow the file card. If the file card has only two arguments, that means the payload is the complete content of the artifact. If the file card has three arguments, then the payload is a delta and second argument is the ID of another artifact that is the source of the delta.</p> <p>File cards are sent in both directions: client to server and server to client. A delta might be sent before the source of the delta, so both client and server should remember deltas and be able to apply them when their source arrives.</p> <h4>3.3.2 Compressed File Cards</h4> <p>A client that sends a clone protocol version "3" or greater will receive artifacts as "cfile" cards while cloning. This card was introduced to improve the speed of the transfer of content by sending the compressed artifact directly from the server database to the client.</p> <p>Compressed File cards are similar to File cards, sharing the same in-line "payload" data characteristics and also the same treatment of direct content or delta content. It comes in two different formats depending on whether the artifact is sent directly or as a delta from some other artifact.</p> <blockquote> <b>cfile</b> <i>artifact-id usize csize</i> <b>\n</b> <i>content</i><br> <b>cfile</b> <i>artifact-id delta-artifact-id usize csize</i> <b>\n</b> <i>content</i><br> </blockquote> <p>The first argument of the cfile card is the ID of the artifact that is being transferred. The artifact ID is the lower-case hexadecimal representation of the SHA1 hash of the artifact. The second argument of the cfile card is the original size in bytes of the artifact. The last argument of the cfile card is the number of compressed bytes of payload that immediately follow the cfile card. If the cfile card has only three arguments, that means the payload is the complete content of the artifact. If the cfile card has four arguments, then the payload is a delta and the second argument is the ID of another artifact that is the source of the delta and the third argument is the original size of the delta artifact.</p> <p>Unlike file cards, cfile cards are only sent in one direction during a clone from server to client for clone protocol version "3" or greater.</p> <h3>3.4 Push and Pull Cards</h3> <p>Among the first cards in a client-to-server message are the push and pull cards. The push card tells the server that the client is pushing content. The pull card tells the server that the client wants to pull content. In the event of a sync, both cards are sent. The format is as follows:</p> |
| ︙ | ︙ | |||
230 231 232 233 234 235 236 | two-argument format.</p> <blockquote> <b>clone</b><br> <b>clone</b> <i>protocol-version sequence-number</i> </blockquote> | | | > > > > > > > | | | 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 | two-argument format.</p> <blockquote> <b>clone</b><br> <b>clone</b> <i>protocol-version sequence-number</i> </blockquote> <h4>3.5.1 Protocol 3</h4> <p>The latest clients send a two-argument clone message with a protocol version of "3". (Future versions of Fossil might use larger protocol version numbers.) Version "3" of the protocol enhanced version "2" by introducing the "cfile" card which is intended to speed up clone operations. Instead of sending "file" cards, the server will send "cfile" cards</p> <h4>3.5.2 Protocol 2</h4> <p>The sequence-number sent is the number of artifacts received so far. For the first clone message, the sequence number is 0. The server will respond by sending file cards for some number of artifacts up to the maximum message size. <p>The server will also send a single "clone_seqno" card to the client so that the client can know where the server left off. <blockquote> <b>clone_seqno</b> <i>sequence-number</i> </blockquote> <p>The clone message in subsequent HTTP requests for the same clone operation will use the sequence-number from the clone_seqno of the previous reply.</p> <p>In response to an initial clone message, the server also sends the client a push message so that the client can discover the projectcode for this project.</p> <h4>3.5.3 Legacy Protocol</h4> <p>Older clients send a clone card with no argument. The server responds to a blank clone card by sending an "igot" card for every artifact in the repository. The client will then issue "gimme" cards to pull down all the content it needs. <p>The legacy protocol works well for smaller repositories (50MB with 50,000 |
| ︙ | ︙ |