Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Added the "e" capability for viewing ticket submitter email addresses. Additional tinkering toward the design of tickets. This check-in is only thinly tested. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
929d28e358248b19de0186fe0e82519a |
| User & Date: | drh 2007-11-05 02:42:58.000 |
Context
|
2007-11-07
| ||
| 22:22 | Improvements to the merge algorithm so that it works better for common changes. Still more work needed. ... (check-in: ac6bb3ce06 user: drh tags: trunk) | |
|
2007-11-05
| ||
| 02:42 | Added the "e" capability for viewing ticket submitter email addresses. Additional tinkering toward the design of tickets. This check-in is only thinly tested. ... (check-in: 929d28e358 user: drh tags: trunk) | |
|
2007-11-03
| ||
| 04:39 | Add support for built-in variables in subscript. ... (check-in: a67fbd784d user: drh tags: trunk) | |
Changes
Changes to src/login.c.
| ︙ | ︙ | |||
289 290 291 292 293 294 295 |
int i;
for(i=0; zCap[i]; i++){
switch( zCap[i] ){
case 's': g.okSetup = 1;
case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okQuery =
g.okRdWiki = g.okWrWiki = g.okNewWiki =
g.okApndWiki = g.okHistory = g.okClone =
| | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
int i;
for(i=0; zCap[i]; i++){
switch( zCap[i] ){
case 's': g.okSetup = 1;
case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okQuery =
g.okRdWiki = g.okWrWiki = g.okNewWiki =
g.okApndWiki = g.okHistory = g.okClone =
g.okNewTkt = g.okPassword = g.okRdAddr = 1;
case 'i': g.okRead = g.okWrite = 1; break;
case 'o': g.okRead = 1; break;
case 'd': g.okDelete = 1; break;
case 'h': g.okHistory = 1; break;
case 'g': g.okClone = 1; break;
case 'p': g.okPassword = 1; break;
case 'q': g.okQuery = 1; break;
case 'j': g.okRdWiki = 1; break;
case 'k': g.okWrWiki = g.okRdWiki = g.okApndWiki =1; break;
case 'm': g.okApndWiki = 1; break;
case 'f': g.okNewWiki = 1; break;
case 'e': g.okRdAddr = 1; break;
case 'r': g.okRdTkt = 1; break;
case 'n': g.okNewTkt = 1; break;
case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
g.okApndTkt = 1; break;
case 'c': g.okApndTkt = 1; break;
}
}
}
/*
** If the current login lacks any of the capabilities listed in
** the input, then return 0. If all capabilities are present, then
** return 1.
*/
int login_has_capability(const char *zCap, int nCap){
int i;
int rc = 1;
if( nCap<0 ) nCap = strlen(zCap);
for(i=0; i<nCap && rc && zCap[i]; i++){
switch( zCap[i] ){
case 'a': rc = g.okAdmin; break;
case 'c': rc = g.okApndTkt; break;
case 'd': rc = g.okDelete; break;
case 'e': rc = g.okRdAddr; break;
case 'f': rc = g.okNewWiki; break;
case 'g': rc = g.okClone; break;
case 'h': rc = g.okHistory; break;
case 'i': rc = g.okWrite; break;
case 'j': rc = g.okRdWiki; break;
case 'k': rc = g.okWrWiki; break;
case 'm': rc = g.okApndWiki; break;
case 'n': rc = g.okNewTkt; break;
case 'o': rc = g.okRead; break;
case 'p': rc = g.okPassword; break;
case 'q': rc = g.okQuery; break;
case 'r': rc = g.okRdTkt; break;
case 's': rc = g.okSetup; break;
case 'w': rc = g.okWrTkt; break;
default: rc = 0; break;
}
}
return rc;
}
/*
** Call this routine when the credential check fails. It causes
** a redirect to the "login" page.
*/
void login_needed(void){
const char *zUrl = PD("REQUEST_URI", "index");
cgi_redirect(mprintf("login?g=%T", zUrl));
/* NOTREACHED */
assert(0);
}
|
Changes to src/main.c.
| ︙ | ︙ | |||
101 102 103 104 105 106 107 108 109 110 111 112 113 114 | int okNewWiki; /* f: create new wiki via web */ int okApndWiki; /* m: append to wiki via web */ int okWrWiki; /* k: edit wiki via web */ int okRdTkt; /* r: view tickets via web */ int okNewTkt; /* n: create new tickets */ int okApndTkt; /* c: append to tickets via the web */ int okWrTkt; /* w: make changes to tickets via web */ FILE *fDebug; /* Write debug information here, if the file exists */ }; /* ** Macro for debugging: */ | > | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | int okNewWiki; /* f: create new wiki via web */ int okApndWiki; /* m: append to wiki via web */ int okWrWiki; /* k: edit wiki via web */ int okRdTkt; /* r: view tickets via web */ int okNewTkt; /* n: create new tickets */ int okApndTkt; /* c: append to tickets via the web */ int okWrTkt; /* w: make changes to tickets via web */ int okRdAddr; /* e: read email addresses on tickets */ FILE *fDebug; /* Write debug information here, if the file exists */ }; /* ** Macro for debugging: */ |
| ︙ | ︙ |
Changes to src/sample-config1.txt.
| ︙ | ︙ | |||
77 78 79 80 81 82 83 | [submitbutton] </td> <td>After filling in the information above, press this button to create the new ticket</td> </tr> </table> [/status /Open default_value] | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | > | | | | | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
[submitbutton]
</td>
<td>After filling in the information above, press this button to create
the new ticket</td>
</tr>
</table>
[/status /Open default_value]
} /new setpage
######################################################################
{
[
# Extract the current information from the ticket table
{SELECT type, status, subsystem, priority,
severity, contact, title, comment
FROM ticket
WHERE tktid=:name} db_prepare
/name {} cgi_parameter {:name} db_bind
db_exec
if /title exists not {
{<i>No such ticket: } puts
/name {} cgi_parameter htmlize puts
{</i>} puts
return
} endif
/title title cgiparam /vtitle store
/status status cgiparam /vstatus store
/type type cgiparam /vtype store
if /submit cgiexists {
/name {} cgi_parameter login ticketchng_begin
if /apndcom cgiexists {
{+comment}
{<hr><i>Added by }
login htmlize concat
{ on } concat
datetime concat
{:</i><br} concat
/apndcom {} cgi_parameter htmlize concat
ticketchng_field
} else {
if vcomment comment eq not {/comment vcomment ticketchng_field} endif
} endif
if vtitle title eq not {/title vtitle ticketchng_field} endif
ticketchng_submit
baseurl /tktview?name= concat /name {} cgi_parameter concat redirect
} endif
]
<form method="POST" action="[baseurl]/tktedit">
<table cellpadding="5">
<tr><td align="right">Title:</td><td>
<input type="text" name="title" value="[vtitle htmlize puts] size=60">
</td></tr>
<tr><td align="right">Status:</td><td>
[vstatus /status status_choices 20 combobox]
</td></tr>
<tr><td align="right">Type:</td><td>
[vtype /type type_choices 20 combobox]
</td></tr>
<tr><td align="right">Severity:</td><td>
[vseverity /severity {High Medium Low} 10 combobox]
</td></tr>
<tr><td align="right">Priority:</td><td>
[vpriority /priority {High Medium Low} 10 combobox]
</td></tr>
<tr><td align="right">Resolution:</td><td>
[vresolution /resolution resolution_choices 20 combobox]
</td></tr>
<tr><td align="right">Subsystem:</td><td>
[vsubsystem /subsystem subsystem_choices 30 combobox]
</td></tr>
[{e} hascap enable_output]
<tr><td align="right">Contact:</td><td>
<input type="text" name="contact" size="40" value="[vcontact htmlize puts]">
</td></tr>
[1 enable_output]
<tr><td align="right">Version Found In:</td><td>
<input type="text" name="foundin" size="50" value="[foundin htmlize puts]">
</td></tr>
<tr><td colspan="2">
[w hascap /eall 0 paramget and /eall store]
[eall enable_output]
Description And Comments:<br>
<textarea name="comment" cols="80" rows="[comment linecount 15 max 10 min]"
wrap="virtual" class="wikiedit">[comment htmlize puts]</textarea><br>
<input type="submit" name="aonly" value="Append Remark">
[eall not enable_output]
Append Remark:<br>
[/comment /cmappnd 70 /cmappnd linecount 10 max multilineappend]<br>
[ok_wrtkt enable_output /eall {Edit All} auxbutton]
[1 enable_output]
</td></tr>
<tr><td align="right"></td><td>
[{Submit Changes} submitbutton]
</td></tr>
</table>
} /edit setpage
######################################################################
{
<table cellpadding="5">
<tr><td align="right">Title:</td><td>
[/title htmlize]
</td></tr>
<tr><td align="right">Status:</td><td>
[/status textview]
</td></tr>
<tr><td align="right">Type:</td><td>
[/type textview]
</td></tr>
<tr><td align="right">Severity:</td><td>
[/severity textview]
</td></tr>
<tr><td align="right">Priority:</td><td>
[/priority textview]
</td></tr>
<tr><td align="right">Resolution:</td><td>
[/priority textview]
</td></tr>
<tr><td align="right">Subsystem:</td><td>
[/subsystem textview]
</td></tr>
[{e} hascap enable_output]
<tr><td align="right">Contact:</td><td>
[/contact textview]
</td></tr>
[1 enable_output]
<tr><td align="right">Version Found In:</td><td>
[/foundin textview]
</td></tr>
<tr><td colspan="2">
Description And Comments:<br>
[/comment wikiview]
</td></tr>
</table>
} /view setpage
##############
# Verb list:
#
# CNEV
# **** VALUE NAME set
# *--- LIST setfields
|
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
124 125 126 127 128 129 130 131 132 133 134 135 136 137 | @ <b>Notes:</b> @ <ol> @ <li><p>The permission flags are as follows:</p> @ <ol type="a"> @ <li value="1"><b>Admin</b>: Create and delete users</li> @ <li value="3"><b>Append-Tkt</b>: Append to tickets</li> @ <li value="4"><b>Delete</b>: Delete wiki and tickets</li> @ <li value="6"><b>New-Wiki</b>: Create new wiki pages</li> @ <li value="7"><b>Clone</b>: Clone the repository</li> @ <li value="8"><b>History</b>: View detail repository history</li> @ <li value="9"><b>Check-In</b>: Commit new versions in the repository</li> @ <li value="10"><b>Read-Wiki</b>: View wiki pages</li> @ <li value="11"><b>Write-Wiki</b>: Edit wiki pages</li> @ <li value="13"><b>Append-Wiki</b>: Append to wiki pages</li> | > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | @ <b>Notes:</b> @ <ol> @ <li><p>The permission flags are as follows:</p> @ <ol type="a"> @ <li value="1"><b>Admin</b>: Create and delete users</li> @ <li value="3"><b>Append-Tkt</b>: Append to tickets</li> @ <li value="4"><b>Delete</b>: Delete wiki and tickets</li> @ <li value="5"><b>Email</b>: View EMail addresses on tickets</li> @ <li value="6"><b>New-Wiki</b>: Create new wiki pages</li> @ <li value="7"><b>Clone</b>: Clone the repository</li> @ <li value="8"><b>History</b>: View detail repository history</li> @ <li value="9"><b>Check-In</b>: Commit new versions in the repository</li> @ <li value="10"><b>Read-Wiki</b>: View wiki pages</li> @ <li value="11"><b>Write-Wiki</b>: Edit wiki pages</li> @ <li value="13"><b>Append-Wiki</b>: Append to wiki pages</li> |
| ︙ | ︙ | |||
158 159 160 161 162 163 164 |
}
/*
** WEBPAGE: /setup_uedit
*/
void user_edit(void){
const char *zId, *zLogin, *zInfo, *zCap;
| | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
}
/*
** WEBPAGE: /setup_uedit
*/
void user_edit(void){
const char *zId, *zLogin, *zInfo, *zCap;
char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap;
char *oak, *oad, *oaq, *oac, *oaf, *oam, *oah, *oag, *oae;
int doWrite;
int uid;
int higherUser = 0; /* True if user being edited is SETUP and the */
/* user doing the editing is ADMIN. Disallow editing */
/* Must have ADMIN privleges to access this page
*/
|
| ︙ | ︙ | |||
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 |
if( doWrite ){
const char *zPw;
const char *zLogin;
char zCap[30];
int i = 0;
int aa = P("aa")!=0;
int ad = P("ad")!=0;
int ai = P("ai")!=0;
int aj = P("aj")!=0;
int ak = P("ak")!=0;
int an = P("an")!=0;
int ao = P("ao")!=0;
int ap = P("ap")!=0;
int aq = P("aq")!=0;
int ar = P("ar")!=0;
int as = g.okSetup && P("as")!=0;
int aw = P("aw")!=0;
int ac = P("ac")!=0;
int af = P("af")!=0;
int am = P("am")!=0;
int ah = P("ah")!=0;
int ag = P("ag")!=0;
if( aa ){ zCap[i++] = 'a'; }
if( ac ){ zCap[i++] = 'c'; }
if( ad ){ zCap[i++] = 'd'; }
if( af ){ zCap[i++] = 'f'; }
if( ah ){ zCap[i++] = 'h'; }
if( ag ){ zCap[i++] = 'g'; }
if( ai ){ zCap[i++] = 'i'; }
if( aj ){ zCap[i++] = 'j'; }
if( ak ){ zCap[i++] = 'k'; }
if( am ){ zCap[i++] = 'm'; }
| > > | 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 |
if( doWrite ){
const char *zPw;
const char *zLogin;
char zCap[30];
int i = 0;
int aa = P("aa")!=0;
int ad = P("ad")!=0;
int ae = P("ae")!=0;
int ai = P("ai")!=0;
int aj = P("aj")!=0;
int ak = P("ak")!=0;
int an = P("an")!=0;
int ao = P("ao")!=0;
int ap = P("ap")!=0;
int aq = P("aq")!=0;
int ar = P("ar")!=0;
int as = g.okSetup && P("as")!=0;
int aw = P("aw")!=0;
int ac = P("ac")!=0;
int af = P("af")!=0;
int am = P("am")!=0;
int ah = P("ah")!=0;
int ag = P("ag")!=0;
if( aa ){ zCap[i++] = 'a'; }
if( ac ){ zCap[i++] = 'c'; }
if( ad ){ zCap[i++] = 'd'; }
if( ae ){ zCap[i++] = 'e'; }
if( af ){ zCap[i++] = 'f'; }
if( ah ){ zCap[i++] = 'h'; }
if( ag ){ zCap[i++] = 'g'; }
if( ai ){ zCap[i++] = 'i'; }
if( aj ){ zCap[i++] = 'j'; }
if( ak ){ zCap[i++] = 'k'; }
if( am ){ zCap[i++] = 'm'; }
|
| ︙ | ︙ | |||
262 263 264 265 266 267 268 | } /* Load the existing information about the user, if any */ zLogin = ""; zInfo = ""; zCap = ""; | | > | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
}
/* Load the existing information about the user, if any
*/
zLogin = "";
zInfo = "";
zCap = "";
oaa = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam =
oan = oao = oap = oaq = oar = oas = oaw = "";
if( uid ){
zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
if( strchr(zCap, 'a') ) oaa = " checked";
if( strchr(zCap, 'c') ) oac = " checked";
if( strchr(zCap, 'd') ) oad = " checked";
if( strchr(zCap, 'e') ) oae = " checked";
if( strchr(zCap, 'f') ) oaf = " checked";
if( strchr(zCap, 'g') ) oag = " checked";
if( strchr(zCap, 'h') ) oah = " checked";
if( strchr(zCap, 'i') ) oai = " checked";
if( strchr(zCap, 'j') ) oaj = " checked";
if( strchr(zCap, 'k') ) oak = " checked";
if( strchr(zCap, 'm') ) oam = " checked";
|
| ︙ | ︙ | |||
322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
@ <td align="right" valign="top">Capabilities:</td>
@ <td>
if( g.okSetup ){
@ <input type="checkbox" name="as"%s(oas)>Setup</input><br>
}
@ <input type="checkbox" name="aa"%s(oaa)>Admin</input><br>
@ <input type="checkbox" name="ad"%s(oad)>Delete</input><br>
@ <input type="checkbox" name="ap"%s(oap)>Password</input><br>
@ <input type="checkbox" name="aq"%s(oaq)>Query</input><br>
@ <input type="checkbox" name="ai"%s(oai)>Check-In</input><br>
@ <input type="checkbox" name="ao"%s(oao)>Check-Out</input><br>
@ <input type="checkbox" name="ah"%s(oah)>History</input><br>
@ <input type="checkbox" name="ag"%s(oag)>Clone</input><br>
@ <input type="checkbox" name="aj"%s(oaj)>Read Wiki</input><br>
| > | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
@ <td align="right" valign="top">Capabilities:</td>
@ <td>
if( g.okSetup ){
@ <input type="checkbox" name="as"%s(oas)>Setup</input><br>
}
@ <input type="checkbox" name="aa"%s(oaa)>Admin</input><br>
@ <input type="checkbox" name="ad"%s(oad)>Delete</input><br>
@ <input type="checkbox" name="ae"%s(oad)>Email</input><br>
@ <input type="checkbox" name="ap"%s(oap)>Password</input><br>
@ <input type="checkbox" name="aq"%s(oaq)>Query</input><br>
@ <input type="checkbox" name="ai"%s(oai)>Check-In</input><br>
@ <input type="checkbox" name="ao"%s(oao)>Check-Out</input><br>
@ <input type="checkbox" name="ah"%s(oah)>History</input><br>
@ <input type="checkbox" name="ag"%s(oag)>Clone</input><br>
@ <input type="checkbox" name="aj"%s(oaj)>Read Wiki</input><br>
|
| ︙ | ︙ |
Changes to src/subscript.c.
| ︙ | ︙ | |||
78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
#define SBSTT_NAME 2 /* ex: /abcde */
#define SBSTT_VERB 3 /* ex: abcde */
#define SBSTT_STRING 4 /* ex: {...} */
#define SBSTT_INTEGER 5 /* Integer including option sign */
#define SBSTT_INCOMPLETE 6 /* Unterminated string token */
#define SBSTT_UNKNOWN 7 /* Unknown token */
#define SBSTT_EOF 8 /* End of input */
/*
** Given an input string z of length n, identify the token that
** starts at z[0]. Write the token type into *pTokenType and
** return the length of the token.
*/
static int sbs_next_token(const char *z, int n, int *pTokenType){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
#define SBSTT_NAME 2 /* ex: /abcde */
#define SBSTT_VERB 3 /* ex: abcde */
#define SBSTT_STRING 4 /* ex: {...} */
#define SBSTT_INTEGER 5 /* Integer including option sign */
#define SBSTT_INCOMPLETE 6 /* Unterminated string token */
#define SBSTT_UNKNOWN 7 /* Unknown token */
#define SBSTT_EOF 8 /* End of input */
/*
** Values are stored in the hash table as instances of the following
** structure.
*/
typedef struct SbSValue SbSValue;
struct SbSValue {
int flags; /* Bitmask of SBSVAL_* values */
union {
struct {
int size; /* Number of bytes in string, not counting final zero */
char *z; /* Pointer to string content */
} str; /* Value if SBSVAL_STR */
struct {
int (*xVerb)(Subscript*, void*); /* Function to do the work */
void *pArg; /* 2nd parameter to xVerb */
} verb; /* Value if SBSVAL_VERB */
} u;
};
#define SBSVAL_VERB 0x0001 /* Value stored in u.verb */
#define SBSVAL_STR 0x0002 /* Value stored in u.str */
#define SBSVAL_DYN 0x0004 /* u.str.z is dynamically allocated */
#define SBSVAL_EXEC 0x0008 /* u.str.z is a script */
/*
** An entry in the hash table is an instance of this structure.
*/
typedef struct SbsHashEntry SbsHashEntry;
struct SbsHashEntry {
SbsHashEntry *pNext; /* Next entry with the same hash on zKey */
SbSValue val; /* The payload */
int nKey; /* Length of the key */
char zKey[0]; /* The key */
};
/*
** A hash table is an instance of the following structure.
*/
typedef struct SbsHashTab SbsHashTab;
struct SbsHashTab {
SbsHashEntry *aHash[SBSCONFIG_NHASH]; /* The hash table */
};
/*
** An instance of the Subscript interpreter
*/
struct Subscript {
int nStack; /* Number of entries on stack */
SbsHashTab symTab; /* The symbol table */
char zErrMsg[SBSCONFIG_ERRSIZE]; /* Space to write an error message */
SbSValue aStack[SBSCONFIG_NSTACK]; /* The stack */
};
/*
** Given an input string z of length n, identify the token that
** starts at z[0]. Write the token type into *pTokenType and
** return the length of the token.
*/
static int sbs_next_token(const char *z, int n, int *pTokenType){
|
| ︙ | ︙ | |||
147 148 149 150 151 152 153 |
return i;
}
*pTokenType = SBSTT_UNKNOWN;
return 1;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
return i;
}
*pTokenType = SBSTT_UNKNOWN;
return 1;
}
/*
** Release any memory allocated by a value.
*/
static void sbs_value_reset(SbSValue *p){
if( p->flags & SBSVAL_DYN ){
free(p->u.str.z);
p->flags = SBSVAL_STR;
p->u.str.z = "";
p->u.str.size = 0;
}
}
/*
** Compute a hash on a string.
*/
static int sbs_hash(const char *z, int n){
int h = 0;
int i;
for(i=0; i<n; i++){
|
| ︙ | ︙ | |||
290 291 292 293 294 295 296 |
sbs_value_reset(&p->val);
free(p);
}
}
memset(pHash, 0, sizeof(*pHash));
}
| < < < < < < < < < < > > > > > > > > > > > > > | 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 |
sbs_value_reset(&p->val);
free(p);
}
}
memset(pHash, 0, sizeof(*pHash));
}
/*
** Push a value onto the stack of an interpreter
*/
static int sbs_push(Subscript *p, SbSValue *pVal){
if( p->nStack>=SBSCONFIG_NSTACK ){
sqlite3_snprintf(SBSCONFIG_ERRSIZE, p->zErrMsg, "stack overflow");
return SBS_ERROR;
}
p->aStack[p->nStack++] = *pVal;
return SBS_OK;
}
/*
** Create a new subscript interpreter. Return a pointer to the
** new interpreter, or return NULL if malloc fails.
*/
struct Subscript *SbS_Create(void){
Subscript *p;
p = malloc( sizeof(*p) );
if( p ){
memset(p, 0, sizeof(*p));
}
return p;
}
/*
** Destroy an subscript interpreter
*/
void SbS_Destroy(struct Subscript *p){
int i;
sbs_hash_reset(&p->symTab);
|
| ︙ | ︙ | |||
568 569 570 571 572 573 574 |
b = SbS_StackValueInt(p, 1);
switch( (int)pOp ){
case SBSOP_ADD: c = a+b; break;
case SBSOP_SUB: c = a-b; break;
case SBSOP_MUL: c = a*b; break;
case SBSOP_DIV: c = b!=0 ? a/b : 0; break;
case SBSOP_AND: c = a && b; break;
| | > > > > > > > > > > > > > > > > > > > > | > < | | | > | | | | | | | | | < < < < < < < < < < < < | < < < > > < < | | | < > | | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 |
b = SbS_StackValueInt(p, 1);
switch( (int)pOp ){
case SBSOP_ADD: c = a+b; break;
case SBSOP_SUB: c = a-b; break;
case SBSOP_MUL: c = a*b; break;
case SBSOP_DIV: c = b!=0 ? a/b : 0; break;
case SBSOP_AND: c = a && b; break;
case SBSOP_OR: c = a || b; break;
case SBSOP_MIN: c = a<b ? a : b; break;
case SBSOP_MAX: c = a<b ? b : a; break;
}
SbS_Pop(p, 2);
SbS_PushInt(p, c);
return 0;
}
/*
** Subscript command: STRING hascap INTEGER
**
** Return true if the user has all of the capabilities listed.
*/
static int hascapCmd(struct Subscript *p, void *pNotUsed){
const char *z;
int i, n, a;
if( SbS_RequireStack(p, 1, "hascap") ) return 1;
z = SbS_StackValue(p, 0, &n);
a = login_has_capability(z, n);
SbS_Pop(p, 1);
SbS_PushInt(p, a);
}
/*
** Subscript command: STRING puts
*/
static int putsCmd(struct Subscript *p, void *pNotUsed){
int size;
const char *z;
if( SbS_RequireStack(p, 1, "puts") ) return 1;
z = SbS_StackValue(p, 0, &size);
if( g.cgiPanic ){
char *zCopy = mprintf("%.*s", size, z);
cgi_printf("%h", zCopy);
free(zCopy);
}else{
printf("%.*s\n", size, z);
}
SbS_Pop(p, 1);
return 0;
}
/*
** A table of built-in commands
*/
static const struct {
const char *zCmd;
int (*xCmd)(Subscript*,void*);
void *pArg;
} aBuiltin[] = {
{ "add", bopCmd, (void*)SBSOP_AND },
{ "and", bopCmd, (void*)SBSOP_AND },
{ "div", bopCmd, (void*)SBSOP_DIV },
{ "hascap", hascapCmd, 0 },
{ "max", bopCmd, (void*)SBSOP_MAX },
{ "min", bopCmd, (void*)SBSOP_MIN },
{ "mul", bopCmd, (void*)SBSOP_MUL },
{ "not", notCmd, 0 },
{ "or", bopCmd, (void*)SBSOP_OR },
{ "puts", putsCmd, 0 },
{ "set", setCmd, 0 },
{ "sub", bopCmd, (void*)SBSOP_SUB },
};
/*
** Compare a zero-terminated string zPattern against
** an unterminated string zStr of length nStr.
*/
static int compare_cmd(const char *zPattern, const char *zStr, int nStr){
int c = strncmp(zPattern, zStr, nStr);
if( c==0 && zPattern[nStr]!=0 ){
c = -1;
}
return c;
}
/*
** Evaluate the script given by the first nScript bytes of zScript[].
** Return 0 on success and non-zero for an error.
*/
int SbS_Eval(struct Subscript *p, const char *zScript, int nScript){
|
| ︙ | ︙ | |||
689 690 691 692 693 694 695 |
/* If the verb is not in the hash table, look for a
** built-in command */
int upr = sizeof(aBuiltin)/sizeof(aBuiltin[0]) - 1;
int lwr = 0;
rc = SBS_ERROR;
while( upr>=lwr ){
int i = (upr+lwr)/2;
| | < < < < < < < < < < < < < < < < < < < < < < < | 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 |
/* If the verb is not in the hash table, look for a
** built-in command */
int upr = sizeof(aBuiltin)/sizeof(aBuiltin[0]) - 1;
int lwr = 0;
rc = SBS_ERROR;
while( upr>=lwr ){
int i = (upr+lwr)/2;
int c = compare_cmd(aBuiltin[i].zCmd, zScript, n);
if( c==0 ){
rc = aBuiltin[i].xCmd(p, aBuiltin[i].pArg);
break;
}else if( c<0 ){
upr = i-1;
}else{
lwr = i+1;
}
}
}else if( pVal->flags & SBSVAL_VERB ){
rc = pVal->u.verb.xVerb(p, pVal->u.verb.pArg);
}else if( pVal->flags & SBSVAL_EXEC ){
rc = SbS_Eval(p, pVal->u.str.z, pVal->u.str.size);
}else{
rc = SbS_Push(p, pVal->u.str.z, pVal->u.str.size, 0);
}
|
| ︙ | ︙ |