1
2 /*
3 ** This file contains the implementation of all of the TH language
4 ** built-in commands.
5 **
6 ** All built-in commands are implemented using the public interface
7 ** declared in th.h, so this file serves as both a part of the language
8 ** implementation and an example of how to extend the language with
9 ** new commands.
10 */
11
12 #include "config.h"
13 #include "th.h"
14 #include <string.h>
15 #include <assert.h>
16
Th_WrongNumArgs(Th_Interp * interp,const char * zMsg)17 int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg){
18 Th_ErrorMessage(interp, "wrong # args: should be \"", zMsg, -1);
19 return TH_ERROR;
20 }
21
22 /*
23 ** Syntax:
24 **
25 ** catch script ?varname?
26 */
catch_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)27 static int catch_command(
28 Th_Interp *interp,
29 void *ctx,
30 int argc,
31 const char **argv,
32 int *argl
33 ){
34 int rc;
35
36 if( argc!=2 && argc!=3 ){
37 return Th_WrongNumArgs(interp, "catch script ?varname?");
38 }
39
40 rc = Th_Eval(interp, 0, argv[1], -1);
41 if( argc==3 ){
42 int nResult;
43 const char *zResult = Th_GetResult(interp, &nResult);
44 Th_SetVar(interp, argv[2], argl[2], zResult, nResult);
45 }
46
47 Th_SetResultInt(interp, rc);
48 return TH_OK;
49 }
50
51 /*
52 ** TH Syntax:
53 **
54 ** if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN?
55 */
if_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)56 static int if_command(
57 Th_Interp *interp,
58 void *ctx,
59 int argc,
60 const char **argv,
61 int *argl
62 ){
63 int rc = TH_OK;
64
65 int iCond; /* Result of evaluating expression */
66 int i;
67
68 const char *zResult;
69 int nResult;
70
71 if( argc<3 ){
72 goto wrong_args;
73 }
74
75 for(i=0; i<argc && rc==TH_OK; i+=3){
76 if( i>argc-3 ){
77 i = argc-3;
78 iCond = 1;
79 }else{
80 if( TH_OK!=Th_Expr(interp, argv[i+1], argl[i+1]) ){
81 return TH_ERROR;
82 }
83 zResult = Th_GetResult(interp, &nResult);
84 rc = Th_ToInt(interp, zResult, nResult, &iCond);
85 }
86 if( iCond && rc==TH_OK ){
87 rc = Th_Eval(interp, 0, argv[i+2], -1);
88 break;
89 }
90 }
91
92 return rc;
93
94 wrong_args:
95 return Th_WrongNumArgs(interp, "if ...");
96 }
97
98 /*
99 ** TH Syntax:
100 **
101 ** expr expr
102 */
expr_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)103 static int expr_command(
104 Th_Interp *interp,
105 void *ctx,
106 int argc,
107 const char **argv,
108 int *argl
109 ){
110 if( argc!=2 ){
111 return Th_WrongNumArgs(interp, "expr expression");
112 }
113
114 return Th_Expr(interp, argv[1], argl[1]);
115 }
116
117 /*
118 ** Evaluate the th1 script (zBody, nBody) in the local stack frame.
119 ** Return the result of the evaluation, except if the result
120 ** is TH_CONTINUE, return TH_OK instead.
121 */
eval_loopbody(Th_Interp * interp,const char * zBody,int nBody)122 static int eval_loopbody(Th_Interp *interp, const char *zBody, int nBody){
123 int rc = Th_Eval(interp, 0, zBody, nBody);
124 if( rc==TH_CONTINUE ){
125 rc = TH_OK;
126 }
127 return rc;
128 }
129
130 /*
131 ** TH Syntax:
132 **
133 ** for init condition incr script
134 */
for_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)135 static int for_command(
136 Th_Interp *interp,
137 void *ctx,
138 int argc,
139 const char **argv,
140 int *argl
141 ){
142 int rc;
143 int iCond;
144
145 if( argc!=5 ){
146 return Th_WrongNumArgs(interp, "for init condition incr script");
147 }
148
149 /* Evaluate the 'init' script */
150 rc = Th_Eval(interp, 0, argv[1], -1);
151
152 while( rc==TH_OK
153 && TH_OK==(rc = Th_Expr(interp, argv[2], -1))
154 && TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond))
155 && iCond
156 && TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4]))
157 ){
158 rc = Th_Eval(interp, 0, argv[3], -1);
159 }
160
161 if( rc==TH_BREAK ) rc = TH_OK;
162 return rc;
163 }
164
165 /*
166 ** TH Syntax:
167 **
168 ** foreach VARLIST LIST SCRIPT
169 */
foreach_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)170 static int foreach_command(
171 Th_Interp *interp,
172 void *ctx,
173 int argc,
174 const char **argv,
175 int *argl
176 ){
177 int rc;
178 char **azVar = 0;
179 int *anVar;
180 int nVar;
181 char **azValue = 0;
182 int *anValue;
183 int nValue;
184 int ii, jj;
185
186 if( argc!=4 ){
187 return Th_WrongNumArgs(interp, "foreach varlist list script");
188 }
189 rc = Th_SplitList(interp, argv[1], argl[1], &azVar, &anVar, &nVar);
190 if( rc ) return rc;
191 rc = Th_SplitList(interp, argv[2], argl[2], &azValue, &anValue, &nValue);
192 for(ii=0; rc==TH_OK && ii<=nValue-nVar; ii+=nVar){
193 for(jj=0; jj<nVar; jj++){
194 Th_SetVar(interp, azVar[jj], anVar[jj], azValue[ii+jj], anValue[ii+jj]);
195 }
196 rc = eval_loopbody(interp, argv[3], argl[3]);
197 }
198 if( rc==TH_BREAK ) rc = TH_OK;
199 Th_Free(interp, azVar);
200 Th_Free(interp, azValue);
201 return rc;
202 }
203
204
205 /*
206 ** TH Syntax:
207 **
208 ** list ?arg1 ?arg2? ...?
209 */
list_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)210 static int list_command(
211 Th_Interp *interp,
212 void *ctx,
213 int argc,
214 const char **argv,
215 int *argl
216 ){
217 char *zList = 0;
218 int nList = 0;
219 int i;
220
221 for(i=1; i<argc; i++){
222 Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
223 }
224
225 Th_SetResult(interp, zList, nList);
226 Th_Free(interp, zList);
227
228 return TH_OK;
229 }
230
231 /*
232 ** TH Syntax:
233 **
234 ** lappend var ?arg1? ?arg2? ...?
235 **
236 ** Interpret the content of variable var as a list. Create var if it
237 ** does not already exist. Append each argument as a new list element.
238 */
lappend_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)239 static int lappend_command(
240 Th_Interp *interp,
241 void *ctx,
242 int argc,
243 const char **argv,
244 int *argl
245 ){
246 char *zList = 0;
247 int nList = 0;
248 int i, rc;
249
250 if( argc<2 ){
251 return Th_WrongNumArgs(interp, "lappend var ...");
252 }
253 rc = Th_GetVar(interp, argv[1], argl[1]);
254 if( rc==TH_OK ){
255 zList = Th_TakeResult(interp, &nList);
256 }
257
258 for(i=2; i<argc; i++){
259 Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
260 }
261
262 Th_SetVar(interp, argv[1], argl[1], zList, nList);
263 Th_SetResult(interp, zList, nList);
264 Th_Free(interp, zList);
265
266 return TH_OK;
267 }
268
269
270 /*
271 ** TH Syntax:
272 **
273 ** lindex list index
274 */
lindex_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)275 static int lindex_command(
276 Th_Interp *interp,
277 void *ctx,
278 int argc,
279 const char **argv,
280 int *argl
281 ){
282 int iElem;
283 int rc;
284
285 char **azElem;
286 int *anElem;
287 int nCount;
288
289 if( argc!=3 ){
290 return Th_WrongNumArgs(interp, "lindex list index");
291 }
292
293 if( TH_OK!=Th_ToInt(interp, argv[2], argl[2], &iElem) ){
294 return TH_ERROR;
295 }
296
297 rc = Th_SplitList(interp, argv[1], argl[1], &azElem, &anElem, &nCount);
298 if( rc==TH_OK ){
299 if( iElem<nCount && iElem>=0 ){
300 Th_SetResult(interp, azElem[iElem], anElem[iElem]);
301 }else{
302 Th_SetResult(interp, 0, 0);
303 }
304 Th_Free(interp, azElem);
305 }
306
307 return rc;
308 }
309
310 /*
311 ** TH Syntax:
312 **
313 ** llength list
314 */
llength_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)315 static int llength_command(
316 Th_Interp *interp,
317 void *ctx,
318 int argc,
319 const char **argv,
320 int *argl
321 ){
322 int nElem;
323 int rc;
324
325 if( argc!=2 ){
326 return Th_WrongNumArgs(interp, "llength list");
327 }
328
329 rc = Th_SplitList(interp, argv[1], argl[1], 0, 0, &nElem);
330 if( rc==TH_OK ){
331 Th_SetResultInt(interp, nElem);
332 }
333
334 return rc;
335 }
336
337 /*
338 ** TH Syntax:
339 **
340 ** lsearch list string
341 */
lsearch_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)342 static int lsearch_command(
343 Th_Interp *interp,
344 void *ctx,
345 int argc,
346 const char **argv,
347 int *argl
348 ){
349 int rc;
350 char **azElem;
351 int *anElem;
352 int nCount;
353 int i;
354
355 if( argc!=3 ){
356 return Th_WrongNumArgs(interp, "lsearch list string");
357 }
358
359 rc = Th_SplitList(interp, argv[1], argl[1], &azElem, &anElem, &nCount);
360 if( rc==TH_OK ){
361 Th_SetResultInt(interp, -1);
362 for(i=0; i<nCount; i++){
363 if( anElem[i]==argl[2] && 0==memcmp(azElem[i], argv[2], argl[2]) ){
364 Th_SetResultInt(interp, i);
365 break;
366 }
367 }
368 Th_Free(interp, azElem);
369 }
370
371 return rc;
372 }
373
374 /*
375 ** TH Syntax:
376 **
377 ** set varname ?value?
378 */
set_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)379 static int set_command(
380 Th_Interp *interp,
381 void *ctx,
382 int argc,
383 const char **argv,
384 int *argl
385 ){
386 if( argc!=2 && argc!=3 ){
387 return Th_WrongNumArgs(interp, "set varname ?value?");
388 }
389
390 if( argc==3 ){
391 Th_SetVar(interp, argv[1], argl[1], argv[2], argl[2]);
392 }
393 return Th_GetVar(interp, argv[1], argl[1]);
394 }
395
396 /*
397 ** When a new command is created using the built-in [proc] command, an
398 ** instance of the following structure is allocated and populated. A
399 ** pointer to the structure is passed as the context (second) argument
400 ** to function proc_call1() when the new command is executed.
401 */
402 typedef struct ProcDefn ProcDefn;
403 struct ProcDefn {
404 int nParam; /* Number of formal (non "args") parameters */
405 char **azParam; /* Parameter names */
406 int *anParam; /* Lengths of parameter names */
407 char **azDefault; /* Default values */
408 int *anDefault; /* Lengths of default values */
409 int hasArgs; /* True if there is an "args" parameter */
410 char *zProgram; /* Body of proc */
411 int nProgram; /* Number of bytes at zProgram */
412 char *zUsage; /* Usage message */
413 int nUsage; /* Number of bytes at zUsage */
414 };
415
416 /* This structure is used to temporarily store arguments passed to an
417 ** invocation of a command created using [proc]. A pointer to an
418 ** instance is passed as the second argument to the proc_call2() function.
419 */
420 typedef struct ProcArgs ProcArgs;
421 struct ProcArgs {
422 int argc;
423 const char **argv;
424 int *argl;
425 };
426
427 /*
428 ** Each time a command created using [proc] is invoked, a new
429 ** th1 stack frame is allocated (for the proc's local variables) and
430 ** this function invoked.
431 **
432 ** Argument pContext1 points to the associated ProcDefn structure.
433 ** Argument pContext2 points to a ProcArgs structure that contains
434 ** the arguments passed to this specific invocation of the proc.
435 */
proc_call2(Th_Interp * interp,void * pContext1,void * pContext2)436 static int proc_call2(Th_Interp *interp, void *pContext1, void *pContext2){
437 int i;
438 ProcDefn *p = (ProcDefn *)pContext1;
439 ProcArgs *pArgs = (ProcArgs *)pContext2;
440
441 /* Check if there are the right number of arguments. If there are
442 ** not, generate a usage message for the command.
443 */
444 if( (pArgs->argc>(p->nParam+1) && !p->hasArgs)
445 || (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1])
446 ){
447 char *zUsage = 0;
448 int nUsage = 0;
449 Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]);
450 Th_StringAppend(interp, &zUsage, &nUsage, p->zUsage, p->nUsage);
451 Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"", 1);
452 Th_WrongNumArgs(interp, zUsage);
453 Th_Free(interp, zUsage);
454 return TH_ERROR;
455 }
456
457 /* Populate the formal proc parameters. */
458 for(i=0; i<p->nParam; i++){
459 const char *zVal;
460 int nVal;
461 if( pArgs->argc>(i+1) ){
462 zVal = pArgs->argv[i+1];
463 nVal = pArgs->argl[i+1];
464 }else{
465 zVal = p->azDefault[i];
466 nVal = p->anDefault[i];
467 }
468 Th_SetVar(interp, p->azParam[i], p->anParam[i], zVal, nVal);
469 }
470
471 /* Populate the "args" parameter, if it exists */
472 if( p->hasArgs ){
473 char *zArgs = 0;
474 int nArgs = 0;
475 for(i=p->nParam+1; i<pArgs->argc; i++){
476 Th_ListAppend(interp, &zArgs, &nArgs, pArgs->argv[i], pArgs->argl[i]);
477 }
478 Th_SetVar(interp, (const char *)"args", -1, zArgs, nArgs);
479 if(zArgs){
480 Th_Free(interp, zArgs);
481 }
482 }
483
484 Th_SetResult(interp, 0, 0);
485 return Th_Eval(interp, 0, p->zProgram, p->nProgram);
486 }
487
488 /*
489 ** This function is the command callback registered for all commands
490 ** created using the [proc] command. The second argument, pContext,
491 ** is a pointer to the associated ProcDefn structure.
492 */
proc_call1(Th_Interp * interp,void * pContext,int argc,const char ** argv,int * argl)493 static int proc_call1(
494 Th_Interp *interp,
495 void *pContext,
496 int argc,
497 const char **argv,
498 int *argl
499 ){
500 int rc;
501
502 ProcDefn *p = (ProcDefn *)pContext;
503 ProcArgs procargs;
504
505 /* Call function proc_call2(), which will call Th_Eval() to evaluate
506 ** the body of the [proc], in a new Th stack frame. This is so that
507 ** the proc body has its own local variable context.
508 */
509 procargs.argc = argc;
510 procargs.argv = argv;
511 procargs.argl = argl;
512 rc = Th_InFrame(interp, proc_call2, (void *)p, (void *)&procargs);
513
514 if( rc==TH_RETURN ){
515 rc = TH_OK;
516 }
517 if( rc==TH_RETURN2 ){
518 rc = TH_RETURN;
519 }
520 return rc;
521 }
522
523 /*
524 ** This function is registered as the delete callback for all commands
525 ** created using the built-in [proc] command. It is called automatically
526 ** when a command created using [proc] is deleted.
527 **
528 ** It frees the ProcDefn structure allocated when the command was created.
529 */
proc_del(Th_Interp * interp,void * pContext)530 static void proc_del(Th_Interp *interp, void *pContext){
531 ProcDefn *p = (ProcDefn *)pContext;
532 Th_Free(interp, (void *)p->zUsage);
533 Th_Free(interp, (void *)p);
534 }
535
536 /*
537 ** TH Syntax:
538 **
539 ** proc name arglist code
540 */
proc_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)541 static int proc_command(
542 Th_Interp *interp,
543 void *ctx,
544 int argc,
545 const char **argv,
546 int *argl
547 ){
548 int rc;
549 const char *zName;
550
551 ProcDefn *p;
552 int nByte;
553 int i;
554 char *zSpace;
555
556 char **azParam;
557 int *anParam;
558 int nParam;
559
560 char *zUsage = 0; /* Build up a usage message here */
561 int nUsage = 0; /* Number of bytes at zUsage */
562
563 if( argc!=4 ){
564 return Th_WrongNumArgs(interp, "proc name arglist code");
565 }
566 if( Th_SplitList(interp, argv[2], argl[2], &azParam, &anParam, &nParam) ){
567 return TH_ERROR;
568 }
569
570 /* Allocate the new ProcDefn structure. */
571 nByte = sizeof(ProcDefn) + /* ProcDefn structure */
572 (sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */
573 (sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */
574 argl[3] + /* zProgram */
575 argl[2]; /* Space for copies of parameter names and default values */
576 p = (ProcDefn *)Th_Malloc(interp, nByte);
577
578 /* If the last parameter in the parameter list is "args", then set the
579 ** ProcDefn.hasArgs flag. The "args" parameter does not require an
580 ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
581 */
582 if( nParam>0 ){
583 if( anParam[nParam-1]==4 && 0==memcmp(azParam[nParam-1], "args", 4) ){
584 p->hasArgs = 1;
585 nParam--;
586 }
587 }
588
589 p->nParam = nParam;
590 p->azParam = (char **)&p[1];
591 p->anParam = (int *)&p->azParam[nParam];
592 p->azDefault = (char **)&p->anParam[nParam];
593 p->anDefault = (int *)&p->azDefault[nParam];
594 p->zProgram = (char *)&p->anDefault[nParam];
595 memcpy(p->zProgram, argv[3], argl[3]);
596 p->nProgram = argl[3];
597 zSpace = &p->zProgram[p->nProgram];
598
599 for(i=0; i<nParam; i++){
600 char **az;
601 int *an;
602 int n;
603 if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){
604 goto error_out;
605 }
606 if( n<1 || n>2 ){
607 const char expected[] = "expected parameter, got \"";
608 Th_ErrorMessage(interp, expected, azParam[i], anParam[i]);
609 Th_Free(interp, az);
610 goto error_out;
611 }
612 p->anParam[i] = an[0];
613 p->azParam[i] = zSpace;
614 memcpy(zSpace, az[0], an[0]);
615 zSpace += an[0];
616 if( n==2 ){
617 p->anDefault[i] = an[1];
618 p->azDefault[i] = zSpace;
619 memcpy(zSpace, az[1], an[1]);
620 zSpace += an[1];
621 }
622
623 Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ", 1);
624 if( n==2 ){
625 Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"?", 1);
626 Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
627 Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"?", 1);
628 }else{
629 Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
630 }
631
632 Th_Free(interp, az);
633 }
634 assert( zSpace-(char *)p<=nByte );
635
636 /* If there is an "args" parameter, append it to the end of the usage
637 ** message. Set ProcDefn.zUsage to point at the usage message. It will
638 ** be freed along with the rest of the proc-definition by proc_del().
639 */
640 if( p->hasArgs ){
641 Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ?args...?", -1);
642 }
643 p->zUsage = zUsage;
644 p->nUsage = nUsage;
645
646 /* Register the new command with the th1 interpreter. */
647 zName = argv[1];
648 rc = Th_CreateCommand(interp, zName, proc_call1, (void *)p, proc_del);
649 if( rc==TH_OK ){
650 Th_SetResult(interp, 0, 0);
651 }
652
653 Th_Free(interp, azParam);
654 return TH_OK;
655
656 error_out:
657 Th_Free(interp, azParam);
658 Th_Free(interp, zUsage);
659 return TH_ERROR;
660 }
661
662 /*
663 ** TH Syntax:
664 **
665 ** rename oldcmd newcmd
666 */
rename_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)667 static int rename_command(
668 Th_Interp *interp,
669 void *ctx,
670 int argc,
671 const char **argv,
672 int *argl
673 ){
674 if( argc!=3 ){
675 return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
676 }
677 return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]);
678 }
679
680 /*
681 ** TH Syntax:
682 **
683 ** break ?value...?
684 ** continue ?value...?
685 ** ok ?value...?
686 ** error ?value...?
687 */
simple_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)688 static int simple_command(
689 Th_Interp *interp,
690 void *ctx,
691 int argc,
692 const char **argv,
693 int *argl
694 ){
695 if( argc!=1 && argc!=2 ){
696 return Th_WrongNumArgs(interp, "return ?value?");
697 }
698 if( argc==2 ){
699 Th_SetResult(interp, argv[1], argl[1]);
700 }
701 return FOSSIL_PTR_TO_INT(ctx);
702 }
703
704 /*
705 ** TH Syntax:
706 **
707 ** return ?-code code? ?value?
708 */
return_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)709 static int return_command(
710 Th_Interp *interp,
711 void *ctx,
712 int argc,
713 const char **argv,
714 int *argl
715 ){
716 int iCode = TH_RETURN;
717 if( argc<1 || argc>4 ){
718 return Th_WrongNumArgs(interp, "return ?-code code? ?value?");
719 }
720 if( argc>2 ){
721 int rc = Th_ToInt(interp, argv[2], argl[2], &iCode);
722 if( rc!=TH_OK ){
723 return rc;
724 }
725 }
726 if( argc==2 || argc==4 ){
727 Th_SetResult(interp, argv[argc-1], argl[argc-1]);
728 }
729 return iCode;
730 }
731
732 /*
733 ** TH Syntax:
734 **
735 ** string compare STRING1 STRING2
736 */
string_compare_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)737 static int string_compare_command(
738 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
739 ){
740 const char *zRight; int nRight;
741 const char *zLeft; int nLeft;
742
743 int i;
744 int iRes = 0;
745
746 if( argc!=4 ){
747 return Th_WrongNumArgs(interp, "string compare str1 str2");
748 }
749
750 zLeft = argv[2];
751 nLeft = argl[2];
752 zRight = argv[3];
753 nRight = argl[3];
754
755 for(i=0; iRes==0 && i<nLeft && i<nRight; i++){
756 iRes = zLeft[i]-zRight[i];
757 }
758 if( iRes==0 ){
759 iRes = nLeft-nRight;
760 }
761
762 if( iRes<0 ) iRes = -1;
763 if( iRes>0 ) iRes = 1;
764
765 return Th_SetResultInt(interp, iRes);
766 }
767
768 /*
769 ** TH Syntax:
770 **
771 ** string first NEEDLE HAYSTACK
772 */
string_first_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)773 static int string_first_command(
774 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
775 ){
776 int nNeedle;
777 int nHaystack;
778 int iRes = -1;
779
780 if( argc!=4 ){
781 return Th_WrongNumArgs(interp, "string first needle haystack");
782 }
783
784 nNeedle = argl[2];
785 nHaystack = argl[3];
786
787 if( nNeedle && nHaystack && nNeedle<=nHaystack ){
788 const char *zNeedle = argv[2];
789 const char *zHaystack = argv[3];
790 int i;
791
792 for(i=0; i<=(nHaystack-nNeedle); i++){
793 if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
794 iRes = i;
795 break;
796 }
797 }
798 }
799
800 return Th_SetResultInt(interp, iRes);
801 }
802
803 /*
804 ** TH Syntax:
805 **
806 ** string index STRING INDEX
807 */
string_index_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)808 static int string_index_command(
809 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
810 ){
811 int iIndex;
812
813 if( argc!=4 ){
814 return Th_WrongNumArgs(interp, "string index string index");
815 }
816
817 if( argl[3]==3 && 0==memcmp("end", argv[3], 3) ){
818 iIndex = argl[2]-1;
819 }else if( Th_ToInt(interp, argv[3], argl[3], &iIndex) ){
820 Th_ErrorMessage(
821 interp, "Expected \"end\" or integer, got:", argv[3], argl[3]);
822 return TH_ERROR;
823 }
824
825 if( iIndex>=0 && iIndex<argl[2] ){
826 return Th_SetResult(interp, &argv[2][iIndex], 1);
827 }else{
828 return Th_SetResult(interp, 0, 0);
829 }
830 }
831
832 /*
833 ** TH Syntax:
834 **
835 ** string is CLASS STRING
836 */
string_is_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)837 static int string_is_command(
838 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
839 ){
840 if( argc!=4 ){
841 return Th_WrongNumArgs(interp, "string is class string");
842 }
843 if( argl[2]==5 && 0==memcmp(argv[2], "alnum", 5) ){
844 int i;
845 int iRes = 1;
846
847 for(i=0; i<argl[3]; i++){
848 if( !th_isalnum(argv[3][i]) ){
849 iRes = 0;
850 }
851 }
852
853 return Th_SetResultInt(interp, iRes);
854 }else if( argl[2]==6 && 0==memcmp(argv[2], "double", 6) ){
855 double fVal;
856 if( Th_ToDouble(interp, argv[3], argl[3], &fVal)==TH_OK ){
857 return Th_SetResultInt(interp, 1);
858 }
859 return Th_SetResultInt(interp, 0);
860 }else if( argl[2]==7 && 0==memcmp(argv[2], "integer", 7) ){
861 int iVal;
862 if( Th_ToInt(interp, argv[3], argl[3], &iVal)==TH_OK ){
863 return Th_SetResultInt(interp, 1);
864 }
865 return Th_SetResultInt(interp, 0);
866 }else if( argl[2]==4 && 0==memcmp(argv[2], "list", 4) ){
867 if( Th_SplitList(interp, argv[3], argl[3], 0, 0, 0)==TH_OK ){
868 return Th_SetResultInt(interp, 1);
869 }
870 return Th_SetResultInt(interp, 0);
871 }else{
872 Th_ErrorMessage(interp,
873 "Expected alnum, double, integer, or list, got:", argv[2], argl[2]);
874 return TH_ERROR;
875 }
876 }
877
878 /*
879 ** TH Syntax:
880 **
881 ** string last NEEDLE HAYSTACK
882 */
string_last_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)883 static int string_last_command(
884 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
885 ){
886 int nNeedle;
887 int nHaystack;
888 int iRes = -1;
889
890 if( argc!=4 ){
891 return Th_WrongNumArgs(interp, "string last needle haystack");
892 }
893
894 nNeedle = argl[2];
895 nHaystack = argl[3];
896
897 if( nNeedle && nHaystack && nNeedle<=nHaystack ){
898 const char *zNeedle = argv[2];
899 const char *zHaystack = argv[3];
900 int i;
901
902 for(i=nHaystack-nNeedle; i>=0; i--){
903 if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
904 iRes = i;
905 break;
906 }
907 }
908 }
909
910 return Th_SetResultInt(interp, iRes);
911 }
912
913 /*
914 ** TH Syntax:
915 **
916 ** string length STRING
917 */
string_length_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)918 static int string_length_command(
919 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
920 ){
921 if( argc!=3 ){
922 return Th_WrongNumArgs(interp, "string length string");
923 }
924 return Th_SetResultInt(interp, argl[2]);
925 }
926
927 /*
928 ** TH Syntax:
929 **
930 ** string match PATTERN STRING
931 **
932 */
string_match_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)933 static int string_match_command(
934 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
935 ){
936 extern char *fossil_strndup(const char*,int);
937 extern void fossil_free(void*);
938 char *zPat, *zStr;
939 int rc;
940 if( argc!=4 ){
941 return Th_WrongNumArgs(interp, "string match pattern string");
942 }
943 zPat = fossil_strndup(argv[2],argl[2]);
944 zStr = fossil_strndup(argv[3],argl[3]);
945 rc = sqlite3_strglob(zPat,zStr);
946 fossil_free(zPat);
947 fossil_free(zStr);
948 return Th_SetResultInt(interp, !rc);
949 }
950
951 /*
952 ** TH Syntax:
953 **
954 ** string range STRING FIRST LAST
955 */
string_range_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)956 static int string_range_command(
957 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
958 ){
959 int iStart;
960 int iEnd;
961
962 if( argc!=5 ){
963 return Th_WrongNumArgs(interp, "string range string first last");
964 }
965
966 if( argl[4]==3 && 0==memcmp("end", argv[4], 3) ){
967 iEnd = argl[2];
968 }else if( Th_ToInt(interp, argv[4], argl[4], &iEnd) ){
969 Th_ErrorMessage(
970 interp, "Expected \"end\" or integer, got:", argv[4], argl[4]);
971 return TH_ERROR;
972 }
973 if( Th_ToInt(interp, argv[3], argl[3], &iStart) ){
974 return TH_ERROR;
975 }
976
977 if( iStart<0 ) iStart = 0;
978 if( iEnd>=argl[2] ) iEnd = argl[2]-1;
979 if( iStart>iEnd ) iEnd = iStart-1;
980
981 return Th_SetResult(interp, &argv[2][iStart], iEnd-iStart+1);
982 }
983
984 /*
985 ** TH Syntax:
986 **
987 ** string repeat STRING COUNT
988 */
string_repeat_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)989 static int string_repeat_command(
990 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
991 ){
992 int n;
993 int i;
994 int nByte;
995 char *zByte;
996
997 if( argc!=4 ){
998 return Th_WrongNumArgs(interp, "string repeat string n");
999 }
1000 if( Th_ToInt(interp, argv[3], argl[3], &n) ){
1001 return TH_ERROR;
1002 }
1003
1004 nByte = argl[2] * n;
1005 zByte = Th_Malloc(interp, nByte+1);
1006 for(i=0; i<nByte; i+=argl[2]){
1007 memcpy(&zByte[i], argv[2], argl[2]);
1008 }
1009
1010 Th_SetResult(interp, zByte, nByte);
1011 Th_Free(interp, zByte);
1012 return TH_OK;
1013 }
1014
1015 /*
1016 ** TH Syntax:
1017 **
1018 ** string trim STRING
1019 ** string trimleft STRING
1020 ** string trimright STRING
1021 */
string_trim_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1022 static int string_trim_command(
1023 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
1024 ){
1025 int n;
1026 const char *z;
1027
1028 if( argc!=3 ){
1029 return Th_WrongNumArgs(interp, "string trim string");
1030 }
1031 z = argv[2];
1032 n = argl[2];
1033 if( argl[1]<5 || argv[1][4]=='l' ){
1034 while( n && th_isspace(z[0]) ){ z++; n--; }
1035 }
1036 if( argl[1]<5 || argv[1][4]=='r' ){
1037 while( n && th_isspace(z[n-1]) ){ n--; }
1038 }
1039 Th_SetResult(interp, z, n);
1040 return TH_OK;
1041 }
1042
1043 /*
1044 ** TH Syntax:
1045 **
1046 ** info exists VARNAME
1047 */
info_exists_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1048 static int info_exists_command(
1049 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
1050 ){
1051 int rc;
1052
1053 if( argc!=3 ){
1054 return Th_WrongNumArgs(interp, "info exists var");
1055 }
1056 rc = Th_ExistsVar(interp, argv[2], argl[2]);
1057 Th_SetResultInt(interp, rc);
1058 return TH_OK;
1059 }
1060
1061 /*
1062 ** TH Syntax:
1063 **
1064 ** info commands
1065 */
info_commands_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1066 static int info_commands_command(
1067 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
1068 ){
1069 int rc;
1070 char *zElem = 0;
1071 int nElem = 0;
1072
1073 if( argc!=2 ){
1074 return Th_WrongNumArgs(interp, "info commands");
1075 }
1076 rc = Th_ListAppendCommands(interp, &zElem, &nElem);
1077 if( rc!=TH_OK ){
1078 return rc;
1079 }
1080 Th_SetResult(interp, zElem, nElem);
1081 if( zElem ) Th_Free(interp, zElem);
1082 return TH_OK;
1083 }
1084
1085 /*
1086 ** TH Syntax:
1087 **
1088 ** info vars
1089 */
info_vars_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1090 static int info_vars_command(
1091 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
1092 ){
1093 int rc;
1094 char *zElem = 0;
1095 int nElem = 0;
1096
1097 if( argc!=2 ){
1098 return Th_WrongNumArgs(interp, "info vars");
1099 }
1100 rc = Th_ListAppendVariables(interp, &zElem, &nElem);
1101 if( rc!=TH_OK ){
1102 return rc;
1103 }
1104 Th_SetResult(interp, zElem, nElem);
1105 if( zElem ) Th_Free(interp, zElem);
1106 return TH_OK;
1107 }
1108
1109 /*
1110 ** TH Syntax:
1111 **
1112 ** array exists VARNAME
1113 */
array_exists_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1114 static int array_exists_command(
1115 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
1116 ){
1117 int rc;
1118
1119 if( argc!=3 ){
1120 return Th_WrongNumArgs(interp, "array exists var");
1121 }
1122 rc = Th_ExistsArrayVar(interp, argv[2], argl[2]);
1123 Th_SetResultInt(interp, rc);
1124 return TH_OK;
1125 }
1126
1127 /*
1128 ** TH Syntax:
1129 **
1130 ** array names VARNAME
1131 */
array_names_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1132 static int array_names_command(
1133 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
1134 ){
1135 int rc;
1136 char *zElem = 0;
1137 int nElem = 0;
1138
1139 if( argc!=3 ){
1140 return Th_WrongNumArgs(interp, "array names varname");
1141 }
1142 rc = Th_ListAppendArray(interp, argv[2], argl[2], &zElem, &nElem);
1143 if( rc!=TH_OK ){
1144 return rc;
1145 }
1146 Th_SetResult(interp, zElem, nElem);
1147 if( zElem ) Th_Free(interp, zElem);
1148 return TH_OK;
1149 }
1150
1151 /*
1152 ** TH Syntax:
1153 **
1154 ** unset VARNAME
1155 */
unset_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1156 static int unset_command(
1157 Th_Interp *interp,
1158 void *ctx,
1159 int argc,
1160 const char **argv,
1161 int *argl
1162 ){
1163 if( argc!=2 ){
1164 return Th_WrongNumArgs(interp, "unset var");
1165 }
1166 return Th_UnsetVar(interp, argv[1], argl[1]);
1167 }
1168
Th_CallSubCommand(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl,const Th_SubCommand * aSub)1169 int Th_CallSubCommand(
1170 Th_Interp *interp,
1171 void *ctx,
1172 int argc,
1173 const char **argv,
1174 int *argl,
1175 const Th_SubCommand *aSub
1176 ){
1177 if( argc>1 ){
1178 int i;
1179 for(i=0; aSub[i].zName; i++){
1180 const char *zName = aSub[i].zName;
1181 if( th_strlen(zName)==argl[1] && 0==memcmp(zName, argv[1], argl[1]) ){
1182 return aSub[i].xProc(interp, ctx, argc, argv, argl);
1183 }
1184 }
1185 }
1186 if(argc<2){
1187 Th_ErrorMessage(interp, "Expected sub-command for", argv[0], argl[0]);
1188 }else{
1189 Th_ErrorMessage(interp, "Expected sub-command, got:", argv[1], argl[1]);
1190 }
1191 return TH_ERROR;
1192 }
1193
1194 /*
1195 ** TH Syntax:
1196 **
1197 ** string compare STR1 STR2
1198 ** string first NEEDLE HAYSTACK ?STARTINDEX?
1199 ** string index STRING INDEX
1200 ** string is CLASS STRING
1201 ** string last NEEDLE HAYSTACK ?STARTINDEX?
1202 ** string length STRING
1203 ** string range STRING FIRST LAST
1204 ** string repeat STRING COUNT
1205 ** string trim STRING
1206 ** string trimleft STRING
1207 ** string trimright STRING
1208 */
string_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1209 static int string_command(
1210 Th_Interp *interp,
1211 void *ctx,
1212 int argc,
1213 const char **argv,
1214 int *argl
1215 ){
1216 static const Th_SubCommand aSub[] = {
1217 { "compare", string_compare_command },
1218 { "first", string_first_command },
1219 { "index", string_index_command },
1220 { "is", string_is_command },
1221 { "last", string_last_command },
1222 { "length", string_length_command },
1223 { "match", string_match_command },
1224 { "range", string_range_command },
1225 { "repeat", string_repeat_command },
1226 { "trim", string_trim_command },
1227 { "trimleft", string_trim_command },
1228 { "trimright", string_trim_command },
1229 { 0, 0 }
1230 };
1231 return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
1232 }
1233
1234 /*
1235 ** TH Syntax:
1236 **
1237 ** info commands
1238 ** info exists VARNAME
1239 ** info vars
1240 */
info_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1241 static int info_command(
1242 Th_Interp *interp,
1243 void *ctx,
1244 int argc,
1245 const char **argv,
1246 int *argl
1247 ){
1248 static const Th_SubCommand aSub[] = {
1249 { "commands", info_commands_command },
1250 { "exists", info_exists_command },
1251 { "vars", info_vars_command },
1252 { 0, 0 }
1253 };
1254 return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
1255 }
1256
1257 /*
1258 ** TH Syntax:
1259 **
1260 ** array exists VARNAME
1261 ** array names VARNAME
1262 */
array_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1263 static int array_command(
1264 Th_Interp *interp,
1265 void *ctx,
1266 int argc,
1267 const char **argv,
1268 int *argl
1269 ){
1270 static const Th_SubCommand aSub[] = {
1271 { "exists", array_exists_command },
1272 { "names", array_names_command },
1273 { 0, 0 }
1274 };
1275 return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
1276 }
1277
1278 /*
1279 ** Convert the script level frame specification (used by the commands
1280 ** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as
1281 ** used by Th_LinkVar() and Th_Eval(). If successful, write the integer
1282 ** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR
1283 ** and leave an error message in the interpreter result.
1284 */
thToFrame(Th_Interp * interp,const char * zFrame,int nFrame,int * piFrame)1285 static int thToFrame(
1286 Th_Interp *interp,
1287 const char *zFrame,
1288 int nFrame,
1289 int *piFrame
1290 ){
1291 int iFrame;
1292 if( th_isdigit(zFrame[0]) ){
1293 int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame);
1294 if( rc!=TH_OK ) return rc;
1295 iFrame = iFrame * -1;
1296 }else if( zFrame[0]=='#' ){
1297 int rc = Th_ToInt(interp, &zFrame[1], nFrame-1, &iFrame);
1298 if( rc!=TH_OK ) return rc;
1299 iFrame = iFrame + 1;
1300 }else{
1301 return TH_ERROR;
1302 }
1303 *piFrame = iFrame;
1304 return TH_OK;
1305 }
1306
1307 /*
1308 ** TH Syntax:
1309 **
1310 ** uplevel ?LEVEL? SCRIPT
1311 */
uplevel_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1312 static int uplevel_command(
1313 Th_Interp *interp,
1314 void *ctx,
1315 int argc,
1316 const char **argv,
1317 int *argl
1318 ){
1319 int iFrame = -1;
1320
1321 if( argc!=2 && argc!=3 ){
1322 return Th_WrongNumArgs(interp, "uplevel ?level? script...");
1323 }
1324 if( argc==3 && TH_OK!=thToFrame(interp, argv[1], argl[1], &iFrame) ){
1325 return TH_ERROR;
1326 }
1327 return Th_Eval(interp, iFrame, argv[argc-1], -1);
1328 }
1329
1330 /*
1331 ** TH Syntax:
1332 **
1333 ** upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...?
1334 */
upvar_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1335 static int upvar_command(
1336 Th_Interp *interp,
1337 void *ctx,
1338 int argc,
1339 const char **argv,
1340 int *argl
1341 ){
1342 int iVar = 1;
1343 int iFrame = -1;
1344 int rc = TH_OK;
1345 int i;
1346
1347 if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){
1348 iVar++;
1349 }
1350 if( argc==iVar || (argc-iVar)%2 ){
1351 return Th_WrongNumArgs(interp,
1352 "upvar frame othervar myvar ?othervar myvar...?");
1353 }
1354 for(i=iVar; rc==TH_OK && i<argc; i=i+2){
1355 rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]);
1356 }
1357 return rc;
1358 }
1359
1360 /*
1361 ** TH Syntax:
1362 **
1363 ** breakpoint ARGS
1364 **
1365 ** This command does nothing at all. Its purpose in life is to serve
1366 ** as a point for setting breakpoints in a debugger.
1367 */
breakpoint_command(Th_Interp * interp,void * ctx,int argc,const char ** argv,int * argl)1368 static int breakpoint_command(
1369 Th_Interp *interp,
1370 void *ctx,
1371 int argc,
1372 const char **argv,
1373 int *argl
1374 ){
1375 int cnt = 0;
1376 cnt++;
1377 return TH_OK;
1378 }
1379
1380 /*
1381 ** Register the built-in th1 language commands with interpreter interp.
1382 ** Usually this is called soon after interpreter creation.
1383 */
th_register_language(Th_Interp * interp)1384 int th_register_language(Th_Interp *interp){
1385 /* Array of built-in commands. */
1386 struct _Command {
1387 const char *zName;
1388 Th_CommandProc xProc;
1389 void *pContext;
1390 } aCommand[] = {
1391 {"array", array_command, 0},
1392 {"catch", catch_command, 0},
1393 {"expr", expr_command, 0},
1394 {"for", for_command, 0},
1395 {"foreach", foreach_command, 0},
1396 {"if", if_command, 0},
1397 {"info", info_command, 0},
1398 {"lappend", lappend_command, 0},
1399 {"lindex", lindex_command, 0},
1400 {"list", list_command, 0},
1401 {"llength", llength_command, 0},
1402 {"lsearch", lsearch_command, 0},
1403 {"proc", proc_command, 0},
1404 {"rename", rename_command, 0},
1405 {"set", set_command, 0},
1406 {"string", string_command, 0},
1407 {"unset", unset_command, 0},
1408 {"uplevel", uplevel_command, 0},
1409 {"upvar", upvar_command, 0},
1410
1411 {"breakpoint", breakpoint_command, 0},
1412
1413 {"return", return_command, 0},
1414 {"break", simple_command, (void *)TH_BREAK},
1415 {"continue", simple_command, (void *)TH_CONTINUE},
1416 {"error", simple_command, (void *)TH_ERROR},
1417
1418 {0, 0, 0}
1419 };
1420 size_t i;
1421
1422 /* Add the language commands. */
1423 for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
1424 void *ctx;
1425 if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
1426 ctx = aCommand[i].pContext;
1427 Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0);
1428 }
1429
1430 return TH_OK;
1431 }
1432