command.c 23.1 KB
Newer Older
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
 *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
6
 *   oyvind.harboe@zylin.com                                               *
7
 *                                                                         *
8
9
 *   Copyright (C) 2008, Duane Ellis                                       *
 *   openocd@duaneeellis.com                                               *
10
 *                                                                         *
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 *   part of this file is taken from libcli (libcli.sourceforge.net)       *
 *   Copyright (C) David Parrish (david@dparrish.com)                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

33
34
35
36
37
#if !BUILD_ECOSBOARD
/* see Embedder-HOWTO.txt in Jim Tcl project hosted on BerliOS*/
#define JIM_EMBEDDED
#endif

38
// @todo the inclusion of target.h here is a layering violation
39
#include "target.h"
40
#include "command.h"
41
#include "configuration.h"
42
43
#include "log.h"
#include "time_support.h"
44
#include "jim-eventloop.h"
45

oharboe's avatar
oharboe committed
46

oharboe's avatar
oharboe committed
47
int fast_and_dangerous = 0;
48
Jim_Interp *interp = NULL;
oharboe's avatar
oharboe committed
49

50
51
static int run_command(command_context_t *context,
		command_t *c, char *words[], unsigned num_words);
52

53
54
static void tcl_output(void *privData, const char *file, unsigned line,
		const char *function, const char *string)
55
{
zwelch's avatar
zwelch committed
56
	Jim_Obj *tclOutput = (Jim_Obj *)privData;
57
58
59
	Jim_AppendString(interp, tclOutput, string, strlen(string));
}

60
61
extern command_context_t *global_cmd_ctx;

62
63
void script_debug(Jim_Interp *interp, const char *name,
		unsigned argc, Jim_Obj *const *argv)
zwelch's avatar
zwelch committed
64
65
{
	LOG_DEBUG("command - %s", name);
66
67
	for (unsigned i = 0; i < argc; i++)
	{
zwelch's avatar
zwelch committed
68
69
70
71
72
73
74
75
76
77
78
		int len;
		const char *w = Jim_GetString(argv[i], &len);

		/* end of line comment? */
		if (*w == '#')
			break;

		LOG_DEBUG("%s - argv[%d]=%s", name, i, w);
	}
}

79
80
81
82
83
static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	/* the private data is stashed in the interp structure */
	command_t *c;
	command_context_t *context;
84
	int retval;
85
86
87
88
	int i;
	int nwords;
	char **words;

89
90
91
92
93
94
	/* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
	 * get overwritten by running other Jim commands! Treat it as an
	 * emphemeral global variable that is used in lieu of an argument
	 * to the fn and fish it out manually.
	 */
	c = interp->cmdPrivData;
zwelch's avatar
zwelch committed
95
	if (c == NULL)
96
	{
zwelch's avatar
zwelch committed
97
		LOG_ERROR("BUG: interp->cmdPrivData == NULL");
98
99
		return JIM_ERR;
	}
100
	target_call_timer_callbacks_now();
101
102
	LOG_USER_N("%s", ""); /* Keep GDB connection alive*/

zwelch's avatar
zwelch committed
103
	script_debug(interp, c->name, argc, argv);
104

105
106
	words = malloc(sizeof(char *) * argc);
	for (i = 0; i < argc; i++)
107
108
	{
		int len;
zwelch's avatar
zwelch committed
109
		const char *w = Jim_GetString(argv[i], &len);
110
111
112
113
114
115
		if (*w=='#')
		{
			/* hit an end of line comment */
			break;
		}
		words[i] = strdup(w);
116
		if (words[i] == NULL)
117
		{
118
119
120
121
			int j;
			for (j = 0; j < i; j++)
				free(words[j]);
			free(words);
122
123
124
			return JIM_ERR;
		}
	}
125
	nwords = i;
126
127
128

	/* grab the command context from the associated data */
	context = Jim_GetAssocData(interp, "context");
129
	if (context == NULL)
130
	{
131
132
133
134
		/* Tcl can invoke commands directly instead of via command_run_line(). This would
		 * happen when the Jim Tcl interpreter is provided by eCos.
		 */
		context = global_cmd_ctx;
135
	}
136

137
138
139
140
	/* capture log output and return it */
	Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
	/* a garbage collect can happen, so we need a reference count to this object */
	Jim_IncrRefCount(tclOutput);
141

142
	log_add_callback(tcl_output, tclOutput);
143

144
	retval = run_command(context, c, words, nwords);
145

146
147
148
	log_remove_callback(tcl_output, tclOutput);

	/* We dump output into this local variable */
149
	Jim_SetResult(interp, tclOutput);
150
	Jim_DecrRefCount(interp, tclOutput);
ntfreak's avatar
ntfreak committed
151

152
153
154
	for (i = 0; i < nwords; i++)
		free(words[i]);
	free(words);
155

156
157
158
159
160
	int *return_retval = Jim_GetAssocData(interp, "retval");
	if (return_retval != NULL)
	{
		*return_retval = retval;
	}
161

zwelch's avatar
zwelch committed
162
	return (retval == ERROR_OK)?JIM_OK:JIM_ERR;
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
static Jim_Obj *command_name_list(struct command_s *c)
{
	Jim_Obj *cmd_list = c->parent ?
			command_name_list(c->parent) :
			Jim_NewListObj(interp, NULL, 0);
	Jim_ListAppendElement(interp, cmd_list,
			Jim_NewStringObj(interp, c->name, -1));

	return cmd_list;
}

static void command_helptext_add(Jim_Obj *cmd_list, const char *help)
{
	Jim_Obj *cmd_entry = Jim_NewListObj(interp, NULL, 0);
	Jim_ListAppendElement(interp, cmd_entry, cmd_list);
	Jim_ListAppendElement(interp, cmd_entry,
			Jim_NewStringObj(interp, help ? : "", -1));

	/* accumulate help text in Tcl helptext list.  */
	Jim_Obj *helptext = Jim_GetGlobalVariableStr(interp,
			"ocd_helptext", JIM_ERRMSG);
	if (Jim_IsShared(helptext))
		helptext = Jim_DuplicateObj(interp, helptext);
	Jim_ListAppendElement(interp, helptext, cmd_entry);
}

oharboe's avatar
oharboe committed
191
192
193
/* nice short description of source file */
#define __THIS__FILE__ "command.c"

194
195
196
command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
{
	command_t *c, *p;
197

198
199
	if (!context || !name)
		return NULL;
200

201
	c = malloc(sizeof(command_t));
202

203
204
205
206
207
208
	c->name = strdup(name);
	c->parent = parent;
	c->children = NULL;
	c->handler = handler;
	c->mode = mode;
	c->next = NULL;
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
	/* place command in tree */
	if (parent)
	{
		if (parent->children)
		{
			/* find last child */
			for (p = parent->children; p && p->next; p = p->next);
			if (p)
				p->next = c;
		}
		else
		{
			parent->children = c;
		}
	}
	else
	{
		if (context->commands)
		{
			/* find last command */
			for (p = context->commands; p && p->next; p = p->next);
			if (p)
				p->next = c;
		}
		else
		{
			context->commands = c;
		}
	}
239

240
	/* just a placeholder, no handler */
zwelch's avatar
zwelch committed
241
	if (c->handler == NULL)
242
243
		return c;

Zachary T Welch's avatar
Zachary T Welch committed
244
245
246
247
248
	const char *full_name = command_name(c, '_');

	const char *ocd_name = alloc_printf("ocd_%s", full_name);
	Jim_CreateCommand(interp, ocd_name, script_command, c, NULL);
	free((void *)ocd_name);
249

250
	/* we now need to add an overrideable proc */
Zachary T Welch's avatar
Zachary T Welch committed
251
252
253
254
	const char *override_name = alloc_printf("proc %s {args} {"
			"if {[catch {eval ocd_%s $args}] == 0} "
			"{return \"\"} else {return -code error}}",
			full_name, full_name);
255
	Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
256
	free((void *)override_name);
257

Zachary T Welch's avatar
Zachary T Welch committed
258
259
	free((void *)full_name);

260
	command_helptext_add(command_name_list(c), help);
261

262
263
264
	return c;
}

265
266
267
int unregister_all_commands(command_context_t *context)
{
	command_t *c, *c2;
268

269
270
	if (context == NULL)
		return ERROR_OK;
271

zwelch's avatar
zwelch committed
272
	while (NULL != context->commands)
273
274
	{
		c = context->commands;
275

zwelch's avatar
zwelch committed
276
		while (NULL != c->children)
277
278
279
280
281
282
283
284
		{
			c2 = c->children;
			c->children = c->children->next;
			free(c2->name);
			c2->name = NULL;
			free(c2);
			c2 = NULL;
		}
285

286
		context->commands = context->commands->next;
287

288
289
290
		free(c->name);
		c->name = NULL;
		free(c);
291
		c = NULL;
292
	}
293

294
295
296
	return ERROR_OK;
}

297
298
299
int unregister_command(command_context_t *context, char *name)
{
	command_t *c, *p = NULL, *c2;
300

301
302
	if ((!context) || (!name))
		return ERROR_INVALID_ARGUMENTS;
303

304
	/* find command */
305
	c = context->commands;
306

zwelch's avatar
zwelch committed
307
	while (NULL != c)
308
	{
309
310
311
312
313
314
315
316
317
		if (strcmp(name, c->name) == 0)
		{
			/* unlink command */
			if (p)
			{
				p->next = c->next;
			}
			else
			{
318
				/* first element in command list */
319
320
				context->commands = c->next;
			}
321

322
			/* unregister children */
zwelch's avatar
zwelch committed
323
			while (NULL != c->children)
324
			{
325
326
327
328
329
330
				c2 = c->children;
				c->children = c->children->next;
				free(c2->name);
				c2->name = NULL;
				free(c2);
				c2 = NULL;
331
			}
332

333
334
			/* delete command */
			free(c->name);
335
			c->name = NULL;
336
			free(c);
337
338
			c = NULL;
			return ERROR_OK;
339
		}
340

341
342
		/* remember the last command for unlinking */
		p = c;
343
		c = c->next;
344
	}
345

346
347
348
	return ERROR_OK;
}

ntfreak's avatar
ntfreak committed
349
void command_output_text(command_context_t *context, const char *data)
oharboe's avatar
oharboe committed
350
{
zwelch's avatar
zwelch committed
351
	if (context && context->output_handler && data) {
352
		context->output_handler(context, data);
oharboe's avatar
oharboe committed
353
354
355
	}
}

zwelch's avatar
zwelch committed
356
void command_print_sameline(command_context_t *context, const char *format, ...)
357
{
358
	char *string;
359

360
361
362
	va_list ap;
	va_start(ap, format);

oharboe's avatar
oharboe committed
363
	string = alloc_vprintf(format, ap);
364
	if (string != NULL)
365
	{
366
367
		/* we want this collected in the log + we also want to pick it up as a tcl return
		 * value.
368
		 *
369
370
371
		 * The latter bit isn't precisely neat, but will do for now.
		 */
		LOG_USER_N("%s", string);
372
373
		/* We already printed it above */
		/* command_output_text(context, string); */
374
		free(string);
375
376
	}

377
378
	va_end(ap);
}
379

zwelch's avatar
zwelch committed
380
void command_print(command_context_t *context, const char *format, ...)
381
{
382
383
	char *string;

384
385
	va_list ap;
	va_start(ap, format);
386

oharboe's avatar
oharboe committed
387
	string = alloc_vprintf(format, ap);
388
389
	if (string != NULL)
	{
oharboe's avatar
oharboe committed
390
		strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
391
392
		/* we want this collected in the log + we also want to pick it up as a tcl return
		 * value.
393
		 *
394
395
396
		 * The latter bit isn't precisely neat, but will do for now.
		 */
		LOG_USER_N("%s", string);
397
398
		/* We already printed it above */
		/* command_output_text(context, string); */
399
400
401
		free(string);
	}

402
	va_end(ap);
403
404
}

Zachary T Welch's avatar
Zachary T Welch committed
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
static char *__command_name(struct command_s *c, char delim, unsigned extra)
{
	char *name;
	unsigned len = strlen(c->name);
	if (NULL == c->parent) {
		// allocate enough for the name, child names, and '\0'
		name = malloc(len + extra + 1);
		strcpy(name, c->name);
	} else {
		// parent's extra must include both the space and name
		name = __command_name(c->parent, delim, 1 + len + extra);
		char dstr[2] = { delim, 0 };
		strcat(name, dstr);
		strcat(name, c->name);
	}
	return name;
}
char *command_name(struct command_s *c, char delim)
{
	return __command_name(c, delim, 0);
}

427
428
static int run_command(command_context_t *context,
		command_t *c, char *words[], unsigned num_words)
429
{
zwelch's avatar
zwelch committed
430
	int start_word = 0;
431
	if (!((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode)))
432
	{
433
		/* Config commands can not run after the config stage */
zwelch's avatar
zwelch committed
434
		LOG_ERROR("Command '%s' only runs during configuration stage", c->name);
435
		return ERROR_FAIL;
436
	}
437

438
439
440
	int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
	if (retval == ERROR_COMMAND_SYNTAX_ERROR)
	{
441
		/* Print help for command */
Zachary T Welch's avatar
Zachary T Welch committed
442
443
444
445
446
447
		char *full_name = command_name(c, ' ');
		if (NULL != full_name) {
			command_run_linef(context, "help %s", full_name);
			free(full_name);
		} else
			retval = -ENOMEM;
448
449
450
451
452
453
454
455
456
457
	}
	else if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
	{
		/* just fall through for a shutdown request */
	}
	else if (retval != ERROR_OK)
	{
		/* we do not print out an error message because the command *should*
		 * have printed out an error
		 */
458
		LOG_DEBUG("Command failed with error code %d", retval);
459
	}
460
461

	return retval;
462
463
}

464
int command_run_line(command_context_t *context, char *line)
465
{
466
467
468
469
470
	/* all the parent commands have been registered with the interpreter
	 * so, can just evaluate the line as a script and check for
	 * results
	 */
	/* run the line thru a script engine */
zwelch's avatar
zwelch committed
471
	int retval = ERROR_FAIL;
472
	int retcode;
473
474
475
476
477
478
	/* Beware! This code needs to be reentrant. It is also possible
	 * for OpenOCD commands to be invoked directly from Tcl. This would
	 * happen when the Jim Tcl interpreter is provided by eCos for
	 * instance.
	 */
	Jim_DeleteAssocData(interp, "context");
479
	retcode = Jim_SetAssocData(interp, "context", NULL, context);
480
481
482
483
484
485
486
	if (retcode == JIM_OK)
	{
		/* associated the return value */
		Jim_DeleteAssocData(interp, "retval");
		retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
		if (retcode == JIM_OK)
		{
487
			retcode = Jim_Eval_Named(interp, line, __THIS__FILE__, __LINE__);
488

489
			Jim_DeleteAssocData(interp, "retval");
490
		}
491
492
		Jim_DeleteAssocData(interp, "context");
	}
493
	if (retcode == JIM_ERR) {
zwelch's avatar
zwelch committed
494
		if (retval != ERROR_COMMAND_CLOSE_CONNECTION)
495
496
497
498
		{
			/* We do not print the connection closed error message */
			Jim_PrintErrorMessage(interp);
		}
zwelch's avatar
zwelch committed
499
		if (retval == ERROR_OK)
500
501
		{
			/* It wasn't a low level OpenOCD command that failed */
502
			return ERROR_FAIL;
503
504
		}
		return retval;
505
506
507
508
509
510
511
512
	} else if (retcode == JIM_EXIT) {
		/* ignore. */
		/* exit(Jim_GetExitCode(interp)); */
	} else {
		const char *result;
		int reslen;

		result = Jim_GetString(Jim_GetResult(interp), &reslen);
zwelch's avatar
zwelch committed
513
		if (reslen > 0)
514
		{
oharboe's avatar
oharboe committed
515
			int i;
zwelch's avatar
zwelch committed
516
			char buff[256 + 1];
oharboe's avatar
oharboe committed
517
518
519
520
521
522
			for (i = 0; i < reslen; i += 256)
			{
				int chunk;
				chunk = reslen - i;
				if (chunk > 256)
					chunk = 256;
zwelch's avatar
zwelch committed
523
				strncpy(buff, result + i, chunk);
oharboe's avatar
oharboe committed
524
525
526
527
				buff[chunk] = 0;
				LOG_USER_N("%s", buff);
			}
			LOG_USER_N("%s", "\n");
528
		}
zwelch's avatar
zwelch committed
529
		retval = ERROR_OK;
ntfreak's avatar
ntfreak committed
530
	}
531
532
533
	return retval;
}

zwelch's avatar
zwelch committed
534
int command_run_linef(command_context_t *context, const char *format, ...)
oharboe's avatar
oharboe committed
535
{
zwelch's avatar
zwelch committed
536
	int retval = ERROR_FAIL;
oharboe's avatar
oharboe committed
537
538
539
540
	char *string;
	va_list ap;
	va_start(ap, format);
	string = alloc_vprintf(format, ap);
zwelch's avatar
zwelch committed
541
	if (string != NULL)
oharboe's avatar
oharboe committed
542
	{
zwelch's avatar
zwelch committed
543
		retval = command_run_line(context, string);
oharboe's avatar
oharboe committed
544
545
546
547
548
	}
	va_end(ap);
	return retval;
}

oharboe's avatar
oharboe committed
549
void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, const char* line), void *priv)
550
551
552
553
554
555
556
557
558
559
{
	context->output_handler = output_handler;
	context->output_handler_priv = priv;
}

command_context_t* copy_command_context(command_context_t* context)
{
	command_context_t* copy_context = malloc(sizeof(command_context_t));

	*copy_context = *context;
560

561
562
563
564
565
566
567
	return copy_context;
}

int command_done(command_context_t *context)
{
	free(context);
	context = NULL;
568

569
570
571
	return ERROR_OK;
}

572
573
574
575
576
577
578
579
580
581
582
/* find full path to file */
static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	if (argc != 2)
		return JIM_ERR;
	const char *file = Jim_GetString(argv[1], NULL);
	char *full_path = find_file(file);
	if (full_path == NULL)
		return JIM_ERR;
	Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
	free(full_path);
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
	Jim_SetResult(interp, result);
	return JIM_OK;
}

static int jim_echo(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	if (argc != 2)
		return JIM_ERR;
	const char *str = Jim_GetString(argv[1], NULL);
	LOG_USER("%s", str);
	return JIM_OK;
}

static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *cookie)
{
	size_t nbytes;
	const char *ptr;
	Jim_Interp *interp;

	/* make it a char easier to read code */
	ptr = _ptr;
	interp = cookie;
	nbytes = size * n;
	if (ptr == NULL || interp == NULL || nbytes == 0) {
		return 0;
	}

	/* do we have to chunk it? */
	if (ptr[nbytes] == 0)
	{
		/* no it is a C style string */
615
		LOG_USER_N("%s", ptr);
616
617
618
619
		return strlen(ptr);
	}
	/* GRR we must chunk - not null terminated */
	while (nbytes) {
zwelch's avatar
zwelch committed
620
		char chunk[128 + 1];
621
622
623
624
625
626
627
628
629
630
631
		int x;

		x = nbytes;
		if (x > 128) {
			x = 128;
		}
		/* copy it */
		memcpy(chunk, ptr, x);
		/* terminate it */
		chunk[n] = 0;
		/* output it */
632
		LOG_USER_N("%s", chunk);
633
634
635
		ptr += x;
		nbytes -= x;
	}
636

637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
	return n;
}

static size_t openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie)
{
	/* TCL wants to read... tell him no */
	return 0;
}

static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
{
	char *cp;
	int n;
	Jim_Interp *interp;

	n = -1;
	interp = cookie;
	if (interp == NULL)
		return n;

	cp = alloc_vprintf(fmt, ap);
	if (cp)
	{
660
		LOG_USER_N("%s", cp);
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
		n = strlen(cp);
		free(cp);
	}
	return n;
}

static int openocd_jim_fflush(void *cookie)
{
	/* nothing to flush */
	return 0;
}

static char* openocd_jim_fgets(char *s, int size, void *cookie)
{
	/* not supported */
	errno = ENOTSUP;
	return NULL;
}

680
681
682
683
684
685
686
687
688
689
690
691
692
693
static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	if (argc != 2)
		return JIM_ERR;
	int retcode;
	const char *str = Jim_GetString(argv[1], NULL);

	/* capture log output and return it */
	Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
	/* a garbage collect can happen, so we need a reference count to this object */
	Jim_IncrRefCount(tclOutput);

	log_add_callback(tcl_output, tclOutput);

694
	retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
695
696
697
698
699
700
701
702
703
704

	log_remove_callback(tcl_output, tclOutput);

	/* We dump output into this local variable */
	Jim_SetResult(interp, tclOutput);
	Jim_DecrRefCount(interp, tclOutput);

	return retcode;
}

705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
/* sleep command sleeps for <n> miliseconds
 * this is useful in target startup scripts
 */
static int handle_sleep_command(struct command_context_s *cmd_ctx,
		char *cmd, char **args, int argc)
{
	bool busy = false;
	if (argc == 2)
	{
		if (strcmp(args[1], "busy") == 0)
			busy = true;
		else
			return ERROR_COMMAND_SYNTAX_ERROR;
	}
	else if (argc < 1 || argc > 2)
		return ERROR_COMMAND_SYNTAX_ERROR;

	unsigned long duration = 0;
	int retval = parse_ulong(args[0], &duration);
	if (ERROR_OK != retval)
		return retval;

	if (!busy)
	{
		long long then = timeval_ms();
		while (timeval_ms() - then < (long long)duration)
		{
			target_call_timer_callbacks_now();
			usleep(1000);
		}
	}
	else
		busy_sleep(duration);

	return ERROR_OK;
}

static int handle_fast_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	if (argc != 1)
		return ERROR_COMMAND_SYNTAX_ERROR;

	fast_and_dangerous = strcmp("enable", args[0]) == 0;

	return ERROR_OK;
}


753
754
755
command_context_t* command_init()
{
	command_context_t* context = malloc(sizeof(command_context_t));
756
	extern const char startup_tcl[];
duane's avatar
duane committed
757
	const char *HostOs;
758

759
760
761
762
763
	context->mode = COMMAND_EXEC;
	context->commands = NULL;
	context->current_target = 0;
	context->output_handler = NULL;
	context->output_handler_priv = NULL;
764

765
#if !BUILD_ECOSBOARD
766
767
768
769
770
771
772
	Jim_InitEmbedded();
	/* Create an interpreter */
	interp = Jim_CreateInterp();
	/* Add all the Jim core commands */
	Jim_RegisterCoreCommands(interp);
#endif

773
#if defined(_MSC_VER)
duane's avatar
duane committed
774
775
	/* WinXX - is generic, the forward
	 * looking problem is this:
oharboe's avatar
oharboe committed
776
	 *
duane's avatar
duane committed
777
778
779
780
781
	 *   "win32" or "win64"
	 *
	 * "winxx" is generic.
	 */
	HostOs = "winxx";
782
#elif defined(__linux__)
duane's avatar
duane committed
783
	HostOs = "linux";
784
#elif defined(__DARWIN__)
duane's avatar
duane committed
785
	HostOs = "darwin";
786
#elif defined(__CYGWIN__)
duane's avatar
duane committed
787
	HostOs = "cygwin";
788
#elif defined(__MINGW32__)
duane's avatar
duane committed
789
	HostOs = "mingw32";
790
791
#elif defined(__ECOS)
	HostOs = "ecos";
duane's avatar
duane committed
792
#else
793
#warn unrecognized host OS...
duane's avatar
duane committed
794
795
	HostOs = "other";
#endif
796
797
	Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
			Jim_NewStringObj(interp, HostOs , strlen(HostOs)));
duane's avatar
duane committed
798

799
	Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
800
	Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
801
	Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);
802
803
804
805
806
807
808
809
810
811

	/* Set Jim's STDIO */
	interp->cookie_stdin = interp;
	interp->cookie_stdout = interp;
	interp->cookie_stderr = interp;
	interp->cb_fwrite = openocd_jim_fwrite;
	interp->cb_fread = openocd_jim_fread ;
	interp->cb_vfprintf = openocd_jim_vfprintf;
	interp->cb_fflush = openocd_jim_fflush;
	interp->cb_fgets = openocd_jim_fgets;
812

813
#if !BUILD_ECOSBOARD
814
	Jim_EventLoopOnLoad(interp);
815
#endif
zwelch's avatar
zwelch committed
816
	if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl",1) == JIM_ERR)
817
	{
818
		LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
819
820
821
822
		Jim_PrintErrorMessage(interp);
		exit(-1);
	}

823
824
825
826
827
828
829
830
	register_command(context, NULL, "sleep",
			handle_sleep_command, COMMAND_ANY,
			"<n> [busy] - sleep for n milliseconds. "
			"\"busy\" means busy wait");
	register_command(context, NULL, "fast",
			handle_fast_command, COMMAND_ANY,
			"fast <enable/disable> - place at beginning of "
			"config files. Sets defaults to fast and dangerous.");
831

832
833
834
	return context;
}

835
836
837
838
839
840
841
842
843
int command_context_mode(command_context_t *cmd_ctx, enum command_mode mode)
{
	if (!cmd_ctx)
		return ERROR_INVALID_ARGUMENTS;

	cmd_ctx->mode = mode;
	return ERROR_OK;
}

844
void process_jim_events(void)
845
{
846
#if !BUILD_ECOSBOARD
847
848
	static int recursion = 0;

849
	if (!recursion)
850
851
	{
		recursion++;
zwelch's avatar
zwelch committed
852
		Jim_ProcessEvents (interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
853
854
		recursion--;
	}
855
#endif
856
857
}

858
859
860
861
void register_jim(struct command_context_s *cmd_ctx, const char *name, int (*cmd)(Jim_Interp *interp, int argc, Jim_Obj *const *argv), const char *help)
{
	Jim_CreateCommand(interp, name, cmd, NULL, NULL);

zwelch's avatar
zwelch committed
862
	Jim_Obj *cmd_list = Jim_NewListObj(interp, NULL, 0);
863
864
	Jim_ListAppendElement(interp, cmd_list,
			Jim_NewStringObj(interp, name, -1));
865

866
	command_helptext_add(cmd_list, help);
867
}
868
869
870
871

/* return global variable long value or 0 upon failure */
long jim_global_long(const char *variable)
{
zwelch's avatar
zwelch committed
872
	Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, variable, JIM_ERRMSG);
873
	long t;
zwelch's avatar
zwelch committed
874
	if (Jim_GetLong(interp, objPtr, &t) == JIM_OK)
875
876
877
878
879
	{
		return t;
	}
	return 0;
}
880

881
#define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
882
883
	int parse##name(const char *str, type *ul) \
	{ \
884
		if (!*str) \
885
886
		{ \
			LOG_ERROR("Invalid command argument"); \
887
			return ERROR_COMMAND_ARGUMENT_INVALID; \
888
		} \
889
890
		char *end; \
		*ul = func(str, &end, 0); \
891
		if (*end) \
892
		{ \
oharboe's avatar
oharboe committed
893
			LOG_ERROR("Invalid command argument"); \
894
			return ERROR_COMMAND_ARGUMENT_INVALID; \
895
		} \
896
		if ((max == *ul) && (ERANGE == errno)) \
897
		{ \
oharboe's avatar
oharboe committed
898
			LOG_ERROR("Argument overflow"); \
899
			return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
900
		} \
901
		if (min && (min == *ul) && (ERANGE == errno)) \
902
		{ \
oharboe's avatar
oharboe committed
903
			LOG_ERROR("Argument underflow"); \
904
			return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
905
		} \
906
		return ERROR_OK; \
907
	}
908
909
910
911
DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long , strtoul, 0, ULONG_MAX)
DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX)
DEFINE_PARSE_NUM_TYPE(_long, long , strtol, LONG_MIN, LONG_MAX)
DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX)
912
913

#define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
914
	int parse##name(const char *str, type *ul) \
915
916
917
918
919
920
	{ \
		functype n; \
		int retval = parse##funcname(str, &n); \
		if (ERROR_OK != retval) \
			return retval; \
		if (n > max) \
921
			return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
922
		if (min) \
923
			return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
924
925
		*ul = n; \
		return ERROR_OK; \
926
	}
927
928
929

#define DEFINE_PARSE_ULONG(name, type, min, max) \
	DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
930
931
932
933
DEFINE_PARSE_ULONG(_uint, unsigned, 0, UINT_MAX)
DEFINE_PARSE_ULONG(_u32, uint32_t, 0, UINT32_MAX)
DEFINE_PARSE_ULONG(_u16, uint16_t, 0, UINT16_MAX)
DEFINE_PARSE_ULONG(_u8, uint8_t, 0, UINT8_MAX)
934
935
936

#define DEFINE_PARSE_LONG(name, type, min, max) \
	DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
937
938
939
940
DEFINE_PARSE_LONG(_int, int, n < INT_MIN, INT_MAX)
DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX)
DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX)
DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX)