command.c 23.5 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
static int run_command(command_context_t *context,
51
		command_t *c, const 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 + 1));
	words[0] = c->name;
107
	for (i = 0; i < argc; i++)
108
109
	{
		int len;
zwelch's avatar
zwelch committed
110
		const char *w = Jim_GetString(argv[i], &len);
111
112
113
114
115
		if (*w=='#')
		{
			/* hit an end of line comment */
			break;
		}
116
117
		words[i + 1] = strdup(w);
		if (words[i + 1] == NULL)
118
		{
119
120
			int j;
			for (j = 0; j < i; j++)
121
				free(words[j + 1]);
122
			free(words);
123
124
125
			return JIM_ERR;
		}
	}
126
	nwords = i;
127
128
129

	/* grab the command context from the associated data */
	context = Jim_GetAssocData(interp, "context");
130
	if (context == NULL)
131
	{
132
133
134
135
		/* 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;
136
	}
137

138
139
140
141
	/* 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);
142

143
	log_add_callback(tcl_output, tclOutput);
144

145
146
	// turn words[0] into args[-1] with this cast
	retval = run_command(context, c, (const char **)words + 1, nwords);
147

148
149
150
	log_remove_callback(tcl_output, tclOutput);

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

154
	for (i = 0; i < nwords; i++)
155
		free(words[i + 1]);
156
	free(words);
157

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

zwelch's avatar
zwelch committed
164
	return (retval == ERROR_OK)?JIM_OK:JIM_ERR;
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
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
193
194
195
/* nice short description of source file */
#define __THIS__FILE__ "command.c"

Zachary T Welch's avatar
Zachary T Welch committed
196
197
198
199
200
/**
 * Find a command by name from a list of commands.
 * @returns The named command if found, or NULL.
 */
static struct command_s *command_find(struct command_s **head, const char *name)
201
{
Zachary T Welch's avatar
Zachary T Welch committed
202
203
204
205
206
207
208
209
	assert(head);
	for (struct command_s *cc = *head; cc; cc = cc->next)
	{
		if (strcmp(cc->name, name) == 0)
			return cc;
	}
	return NULL;
}
210

Zachary T Welch's avatar
Zachary T Welch committed
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/**
 * Add the command to the end of linked list.
 * @returns Returns false if the named command already exists in the list.
 * Returns true otherwise.
 */
static void command_add_child(struct command_s **head, struct command_s *c)
{
	assert(head);
	if (NULL == *head)
	{
		*head = c;
		return;
	}
	struct command_s *cc = *head;
	while (cc->next) cc = cc->next;
	cc->next = c;
}

command_t* register_command(command_context_t *context,
Zachary T Welch's avatar
Zachary T Welch committed
230
		command_t *parent, char *name, command_handler_t handler,
Zachary T Welch's avatar
Zachary T Welch committed
231
232
		enum command_mode mode, char *help)
{
233
234
	if (!context || !name)
		return NULL;
235

Zachary T Welch's avatar
Zachary T Welch committed
236
237
238
239
240
	struct command_s **head = parent ? &parent->children : &context->commands;
	struct command_s *c = command_find(head, name);
	if (NULL != c)
		return c;

241
	c = malloc(sizeof(command_t));
242

243
244
245
246
247
248
	c->name = strdup(name);
	c->parent = parent;
	c->children = NULL;
	c->handler = handler;
	c->mode = mode;
	c->next = NULL;
249

Zachary T Welch's avatar
Zachary T Welch committed
250
	command_add_child(head, c);
251

252
253
	command_helptext_add(command_name_list(c), help);

254
	/* just a placeholder, no handler */
zwelch's avatar
zwelch committed
255
	if (c->handler == NULL)
256
257
		return c;

Zachary T Welch's avatar
Zachary T Welch committed
258
259
260
261
262
	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);
263

264
	/* we now need to add an overrideable proc */
Zachary T Welch's avatar
Zachary T Welch committed
265
266
267
268
	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);
269
	Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__);
270
	free((void *)override_name);
271

Zachary T Welch's avatar
Zachary T Welch committed
272
273
	free((void *)full_name);

274
275
276
	return c;
}

277
278
279
int unregister_all_commands(command_context_t *context)
{
	command_t *c, *c2;
280

281
282
	if (context == NULL)
		return ERROR_OK;
283

zwelch's avatar
zwelch committed
284
	while (NULL != context->commands)
285
286
	{
		c = context->commands;
287

zwelch's avatar
zwelch committed
288
		while (NULL != c->children)
289
290
291
292
293
294
295
296
		{
			c2 = c->children;
			c->children = c->children->next;
			free(c2->name);
			c2->name = NULL;
			free(c2);
			c2 = NULL;
		}
297

298
		context->commands = context->commands->next;
299

300
301
302
		free(c->name);
		c->name = NULL;
		free(c);
303
		c = NULL;
304
	}
305

306
307
308
	return ERROR_OK;
}

309
310
311
int unregister_command(command_context_t *context, char *name)
{
	command_t *c, *p = NULL, *c2;
312

313
314
	if ((!context) || (!name))
		return ERROR_INVALID_ARGUMENTS;
315

316
	/* find command */
317
	c = context->commands;
318

zwelch's avatar
zwelch committed
319
	while (NULL != c)
320
	{
321
322
323
324
325
326
327
328
329
		if (strcmp(name, c->name) == 0)
		{
			/* unlink command */
			if (p)
			{
				p->next = c->next;
			}
			else
			{
330
				/* first element in command list */
331
332
				context->commands = c->next;
			}
333

334
			/* unregister children */
zwelch's avatar
zwelch committed
335
			while (NULL != c->children)
336
			{
337
338
339
340
341
342
				c2 = c->children;
				c->children = c->children->next;
				free(c2->name);
				c2->name = NULL;
				free(c2);
				c2 = NULL;
343
			}
344

345
346
			/* delete command */
			free(c->name);
347
			c->name = NULL;
348
			free(c);
349
350
			c = NULL;
			return ERROR_OK;
351
		}
352

353
354
		/* remember the last command for unlinking */
		p = c;
355
		c = c->next;
356
	}
357

358
359
360
	return ERROR_OK;
}

ntfreak's avatar
ntfreak committed
361
void command_output_text(command_context_t *context, const char *data)
oharboe's avatar
oharboe committed
362
{
zwelch's avatar
zwelch committed
363
	if (context && context->output_handler && data) {
364
		context->output_handler(context, data);
oharboe's avatar
oharboe committed
365
366
367
	}
}

zwelch's avatar
zwelch committed
368
void command_print_sameline(command_context_t *context, const char *format, ...)
369
{
370
	char *string;
371

372
373
374
	va_list ap;
	va_start(ap, format);

oharboe's avatar
oharboe committed
375
	string = alloc_vprintf(format, ap);
376
	if (string != NULL)
377
	{
378
379
		/* we want this collected in the log + we also want to pick it up as a tcl return
		 * value.
380
		 *
381
382
383
		 * The latter bit isn't precisely neat, but will do for now.
		 */
		LOG_USER_N("%s", string);
384
385
		/* We already printed it above */
		/* command_output_text(context, string); */
386
		free(string);
387
388
	}

389
390
	va_end(ap);
}
391

zwelch's avatar
zwelch committed
392
void command_print(command_context_t *context, const char *format, ...)
393
{
394
395
	char *string;

396
397
	va_list ap;
	va_start(ap, format);
398

oharboe's avatar
oharboe committed
399
	string = alloc_vprintf(format, ap);
400
401
	if (string != NULL)
	{
oharboe's avatar
oharboe committed
402
		strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
403
404
		/* we want this collected in the log + we also want to pick it up as a tcl return
		 * value.
405
		 *
406
407
408
		 * The latter bit isn't precisely neat, but will do for now.
		 */
		LOG_USER_N("%s", string);
409
410
		/* We already printed it above */
		/* command_output_text(context, string); */
411
412
413
		free(string);
	}

414
	va_end(ap);
415
416
}

Zachary T Welch's avatar
Zachary T Welch committed
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
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);
}

439
static int run_command(command_context_t *context,
440
		command_t *c, const char *words[], unsigned num_words)
441
{
zwelch's avatar
zwelch committed
442
	int start_word = 0;
443
	if (!((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode)))
444
	{
445
		/* Config commands can not run after the config stage */
zwelch's avatar
zwelch committed
446
		LOG_ERROR("Command '%s' only runs during configuration stage", c->name);
447
		return ERROR_FAIL;
448
	}
449

450
451
	unsigned argc = num_words - start_word - 1;
	const char **args = words + start_word + 1;
452
	int retval = c->handler(context, args, argc);
453
454
	if (retval == ERROR_COMMAND_SYNTAX_ERROR)
	{
455
		/* Print help for command */
Zachary T Welch's avatar
Zachary T Welch committed
456
457
458
459
460
461
		char *full_name = command_name(c, ' ');
		if (NULL != full_name) {
			command_run_linef(context, "help %s", full_name);
			free(full_name);
		} else
			retval = -ENOMEM;
462
463
464
465
466
467
468
469
470
471
	}
	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
		 */
472
		LOG_DEBUG("Command failed with error code %d", retval);
473
	}
474
475

	return retval;
476
477
}

478
int command_run_line(command_context_t *context, char *line)
479
{
480
481
482
483
484
	/* 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
485
	int retval = ERROR_FAIL;
486
	int retcode;
487
488
489
490
491
492
	/* 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");
493
	retcode = Jim_SetAssocData(interp, "context", NULL, context);
494
495
496
497
498
499
500
	if (retcode == JIM_OK)
	{
		/* associated the return value */
		Jim_DeleteAssocData(interp, "retval");
		retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
		if (retcode == JIM_OK)
		{
501
			retcode = Jim_Eval_Named(interp, line, __THIS__FILE__, __LINE__);
502

503
			Jim_DeleteAssocData(interp, "retval");
504
		}
505
506
		Jim_DeleteAssocData(interp, "context");
	}
507
	if (retcode == JIM_ERR) {
zwelch's avatar
zwelch committed
508
		if (retval != ERROR_COMMAND_CLOSE_CONNECTION)
509
510
511
512
		{
			/* We do not print the connection closed error message */
			Jim_PrintErrorMessage(interp);
		}
zwelch's avatar
zwelch committed
513
		if (retval == ERROR_OK)
514
515
		{
			/* It wasn't a low level OpenOCD command that failed */
516
			return ERROR_FAIL;
517
518
		}
		return retval;
519
520
521
522
523
524
525
526
	} 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
527
		if (reslen > 0)
528
		{
oharboe's avatar
oharboe committed
529
			int i;
zwelch's avatar
zwelch committed
530
			char buff[256 + 1];
oharboe's avatar
oharboe committed
531
532
533
534
535
536
			for (i = 0; i < reslen; i += 256)
			{
				int chunk;
				chunk = reslen - i;
				if (chunk > 256)
					chunk = 256;
zwelch's avatar
zwelch committed
537
				strncpy(buff, result + i, chunk);
oharboe's avatar
oharboe committed
538
539
540
541
				buff[chunk] = 0;
				LOG_USER_N("%s", buff);
			}
			LOG_USER_N("%s", "\n");
542
		}
zwelch's avatar
zwelch committed
543
		retval = ERROR_OK;
ntfreak's avatar
ntfreak committed
544
	}
545
546
547
	return retval;
}

zwelch's avatar
zwelch committed
548
int command_run_linef(command_context_t *context, const char *format, ...)
oharboe's avatar
oharboe committed
549
{
zwelch's avatar
zwelch committed
550
	int retval = ERROR_FAIL;
oharboe's avatar
oharboe committed
551
552
553
554
	char *string;
	va_list ap;
	va_start(ap, format);
	string = alloc_vprintf(format, ap);
zwelch's avatar
zwelch committed
555
	if (string != NULL)
oharboe's avatar
oharboe committed
556
	{
zwelch's avatar
zwelch committed
557
		retval = command_run_line(context, string);
oharboe's avatar
oharboe committed
558
559
560
561
562
	}
	va_end(ap);
	return retval;
}

Zachary T Welch's avatar
Zachary T Welch committed
563
564
void command_set_output_handler(command_context_t* context,
		command_output_handler_t output_handler, void *priv)
565
566
567
568
569
570
571
572
573
574
{
	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;
575

576
577
578
579
580
581
582
	return copy_context;
}

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

584
585
586
	return ERROR_OK;
}

587
588
589
590
591
592
593
594
595
596
597
/* 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);
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
	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 */
630
		LOG_USER_N("%s", ptr);
631
632
633
634
		return strlen(ptr);
	}
	/* GRR we must chunk - not null terminated */
	while (nbytes) {
zwelch's avatar
zwelch committed
635
		char chunk[128 + 1];
636
637
638
639
640
641
642
643
644
645
646
		int x;

		x = nbytes;
		if (x > 128) {
			x = 128;
		}
		/* copy it */
		memcpy(chunk, ptr, x);
		/* terminate it */
		chunk[n] = 0;
		/* output it */
647
		LOG_USER_N("%s", chunk);
648
649
650
		ptr += x;
		nbytes -= x;
	}
651

652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
	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)
	{
675
		LOG_USER_N("%s", cp);
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
		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;
}

695
696
697
698
699
700
701
702
703
704
705
706
707
708
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);

709
	retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
710
711
712
713
714
715
716
717
718
719

	log_remove_callback(tcl_output, tclOutput);

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

	return retcode;
}

720
721
722
/* sleep command sleeps for <n> miliseconds
 * this is useful in target startup scripts
 */
723
COMMAND_HANDLER(handle_sleep_command)
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
{
	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;
}

756
COMMAND_HANDLER(handle_fast_command)
757
758
759
760
761
762
763
764
765
766
{
	if (argc != 1)
		return ERROR_COMMAND_SYNTAX_ERROR;

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

	return ERROR_OK;
}


767
768
769
command_context_t* command_init()
{
	command_context_t* context = malloc(sizeof(command_context_t));
770
	extern const char startup_tcl[];
duane's avatar
duane committed
771
	const char *HostOs;
772

773
774
775
776
777
	context->mode = COMMAND_EXEC;
	context->commands = NULL;
	context->current_target = 0;
	context->output_handler = NULL;
	context->output_handler_priv = NULL;
778

779
#if !BUILD_ECOSBOARD
780
781
782
783
784
785
786
	Jim_InitEmbedded();
	/* Create an interpreter */
	interp = Jim_CreateInterp();
	/* Add all the Jim core commands */
	Jim_RegisterCoreCommands(interp);
#endif

787
#if defined(_MSC_VER)
duane's avatar
duane committed
788
789
	/* WinXX - is generic, the forward
	 * looking problem is this:
oharboe's avatar
oharboe committed
790
	 *
duane's avatar
duane committed
791
792
793
794
795
	 *   "win32" or "win64"
	 *
	 * "winxx" is generic.
	 */
	HostOs = "winxx";
796
#elif defined(__linux__)
duane's avatar
duane committed
797
	HostOs = "linux";
798
#elif defined(__DARWIN__)
duane's avatar
duane committed
799
	HostOs = "darwin";
800
#elif defined(__CYGWIN__)
duane's avatar
duane committed
801
	HostOs = "cygwin";
802
#elif defined(__MINGW32__)
duane's avatar
duane committed
803
	HostOs = "mingw32";
804
805
#elif defined(__ECOS)
	HostOs = "ecos";
duane's avatar
duane committed
806
#else
807
#warn unrecognized host OS...
duane's avatar
duane committed
808
809
	HostOs = "other";
#endif
810
811
	Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
			Jim_NewStringObj(interp, HostOs , strlen(HostOs)));
duane's avatar
duane committed
812

813
	Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
814
	Jim_CreateCommand(interp, "echo", jim_echo, NULL, NULL);
815
	Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);
816
817
818
819
820
821
822
823
824
825

	/* 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;
826

827
#if !BUILD_ECOSBOARD
828
	Jim_EventLoopOnLoad(interp);
829
#endif
zwelch's avatar
zwelch committed
830
	if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl",1) == JIM_ERR)
831
	{
832
		LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)");
833
834
835
836
		Jim_PrintErrorMessage(interp);
		exit(-1);
	}

837
838
839
840
841
842
843
844
	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.");
845

846
847
848
	return context;
}

849
850
851
852
853
854
855
856
857
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;
}

858
void process_jim_events(void)
859
{
860
#if !BUILD_ECOSBOARD
861
862
	static int recursion = 0;

863
	if (!recursion)
864
865
	{
		recursion++;
zwelch's avatar
zwelch committed
866
		Jim_ProcessEvents (interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
867
868
		recursion--;
	}
869
#endif
870
871
}

872
873
874
875
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
876
	Jim_Obj *cmd_list = Jim_NewListObj(interp, NULL, 0);
877
878
	Jim_ListAppendElement(interp, cmd_list,
			Jim_NewStringObj(interp, name, -1));
879

880
	command_helptext_add(cmd_list, help);
881
}
882
883
884
885

/* return global variable long value or 0 upon failure */
long jim_global_long(const char *variable)
{
zwelch's avatar
zwelch committed
886
	Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, variable, JIM_ERRMSG);
887
	long t;
zwelch's avatar
zwelch committed
888
	if (Jim_GetLong(interp, objPtr, &t) == JIM_OK)
889
890
891
892
893
	{
		return t;
	}
	return 0;
}
894

895
#define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
896
897
	int parse##name(const char *str, type *ul) \
	{ \
898
		if (!*str) \
899
900
		{ \
			LOG_ERROR("Invalid command argument"); \
901
			return ERROR_COMMAND_ARGUMENT_INVALID; \
902
		} \
903
904
		char *end; \
		*ul = func(str, &end, 0); \
905
		if (*end) \
906
		{ \
oharboe's avatar
oharboe committed
907
			LOG_ERROR("Invalid command argument"); \
908
			return ERROR_COMMAND_ARGUMENT_INVALID; \
909
		} \
910
		if ((max == *ul) && (ERANGE == errno)) \
911
		{ \
oharboe's avatar
oharboe committed
912
			LOG_ERROR("Argument overflow"); \
913
			return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
914
		} \
915
		if (min && (min == *ul) && (ERANGE == errno)) \
916
		{ \
oharboe's avatar
oharboe committed
917
			LOG_ERROR("Argument underflow"); \
918
			return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
919
		} \
920
		return ERROR_OK; \
921
	}
922
923
924
925
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)
926
927

#define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
928
	int parse##name(const char *str, type *ul) \
929
930
931
932
933
934
	{ \
		functype n; \
		int retval = parse##funcname(str, &n); \
		if (ERROR_OK != retval) \
			return retval; \
		if (n > max) \
935
			return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
936
		if (min) \
937
			return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
938
939
		*ul = n; \
		return ERROR_OK; \
940
	}
941
942
943

#define DEFINE_PARSE_ULONG(name, type, min, max) \
	DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong)
944
945
946
947
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)
948
949
950

#define DEFINE_PARSE_LONG(name, type, min, max) \
	DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long)
951
952
953
954
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)