Background:
I was writing a bunch of tcl/tk scripts to try out Jim - in
OpenOCD... and got stuck.
Jim's FORMAT does not work very well.. It is full of bugs - and
lacking many features
So ... Patch #1 - greatly improves JIM's format command.
And .. JIM does not implement the ARRAY command! grr!!! (I did not fix that)
Patch #2 - Later this weekend.... Tcl Scripts that do "interesting things"
I could not complete them because - of the problems with format...
Will somebody review and if good enough .. commit.
(A) The Patch file..
openocd-patch-jim-format-improvements
(B) a bunch of test examples - for your amusement.
file: BUG.jim
Sadly... There are still bugs... and more more bugs..
And these are not 'regression' type tests...
-Duane.
============
FIXED:
format "%d %d %d" 12 34 56
OLD
printed "12 12 12"
NEW:
prints: 12 34 56
Basically- only the "%s" option supported multiple % items in the format
string.
============
FEATURE LACKING - Now implemented [mostly]
%x - not supported
ditto for: X, E, e, F,g, o, u,D,
And no Format specifiers worked..
ie: "%08x" did not work.
ie: "%+010d" did not work.
... and many more ...
Many - not all work...
The "precision" one is still not implemented (ie: stuff after the "." in
printf)
============
BUG: Inconsistant results: Try this:
telnetprompt> source ./BUG.jim
vrs
telnetprompt > script ./BUG.jim
This is something NON-Jim related, and is specific to how it is
integrated into openocd.
============
This syntax error causes JIM to crash...
for { set x 0 } { $x < 0x$5f } { incr x } { puts "Hi mom" }
Note that in the {test expression} item the syntax error is an extra
$DOLLAR$
==============
FIXED
Calls to strtol() and strtod() to strtol() did not verify a
conversion actually happened.
==============
Index: jim.c
===================================================================
--- jim.c (revision 753)
+++ jim.c (working copy)
@@ -363,7 +363,7 @@
#else
*widePtr = strtol(str, &endptr, base);
#endif
- if (str[0] == '\0')
+ if ((str[0] == '\0') || (str == endptr) )
return JIM_ERR;
if (endptr[0] != '\0') {
while(*endptr) {
@@ -380,7 +380,7 @@
char *endptr;
*intPtr = strtol(str, &endptr, 10);
- if (str[0] == '\0')
+ if ( (str[0] == '\0') || (str == endptr) )
return JIM_ERR;
if (endptr[0] != '\0') {
while(*endptr) {
@@ -437,7 +437,7 @@
char *endptr;
*doublePtr = strtod(str, &endptr);
- if (str[0] == '\0' || endptr[0] != '\0')
+ if (str[0] == '\0' || endptr[0] != '\0' || (str == endptr) )
return JIM_ERR;
return JIM_OK;
}
@@ -2136,21 +2136,36 @@
}
/* This is the core of the [format] command.
- * TODO: Export it, make it real... for now only %s and %%
- * specifiers supported. */
+ * TODO: Lots of things work - via a hack
+ * However, no format item can be >= JIM_MAX_FMT
+ */
Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr,
int objc, Jim_Obj *const *objv)
{
- const char *fmt;
+ const char *fmt, *_fmt;
int fmtLen;
Jim_Obj *resObjPtr;
+
fmt = Jim_GetString(fmtObjPtr, &fmtLen);
+ _fmt = fmt;
resObjPtr = Jim_NewStringObj(interp, "", 0);
while (fmtLen) {
const char *p = fmt;
char spec[2], c;
jim_wide wideValue;
+ double doubleValue;
+ /* we cheat and use Sprintf()! */
+#define JIM_MAX_FMT 2048
+ char sprintf_buf[JIM_MAX_FMT];
+ char fmt_str[100];
+ char *cp;
+ int width;
+ int ljust;
+ int zpad;
+ int spad;
+ int altfm;
+ int forceplus;
while (*fmt != '%' && fmtLen) {
fmt++; fmtLen--;
@@ -2159,38 +2174,189 @@
if (fmtLen == 0)
break;
fmt++; fmtLen--; /* skip '%' */
- if (*fmt != '%') {
+ zpad = 0;
+ spad = 0;
+ width = -1;
+ ljust = 0;
+ altfm = 0;
+ forceplus = 0;
+ next_fmt:
+ if( fmtLen <= 0 ){
+ break;
+ }
+ switch( *fmt ){
+ /* terminals */
+ case 's': /* string */
+ case 'i': /* integer */
+ case 'd': /* decimal */
+ case 'x': /* hex */
+ case 'X': /* CAP hex */
+ case 'c': /* char */
+ case 'o': /* octal */
+ case 'u': /* unsigned */
+ case 'f': /* float */
+ break;
+
+ /* non-terminals */
+ case '0': /* zero pad */
+ zpad = 1;
+ *fmt++; fmtLen--;
+ goto next_fmt;
+ break;
+ case '+':
+ forceplus = 1;
+ *fmt++; fmtLen--;
+ goto next_fmt;
+ break;
+ case ' ': /* sign space */
+ spad = 1;
+ *fmt++; fmtLen--;
+ goto next_fmt;
+ break;
+ case '-':
+ ljust = 1;
+ *fmt++; fmtLen--;
+ goto next_fmt;
+ break;
+ case '#':
+ altfm = 1;
+ *fmt++; fmtLen--;
+ goto next_fmt;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ width = 0;
+ while( isdigit(*fmt) && (fmtLen > 0) ){
+ width = (width * 10) + (*fmt - '0');
+ fmt++; fmtLen--;
+ }
+ goto next_fmt;
+ case '*':
+ /* suck up the next item as an integer */
+ *fmt++; fmtLen--;
+ objc--;
+ if( objc <= 0 ){
+ goto not_enough_args;
+ }
+ if( Jim_GetWide(interp,objv[0],&wideValue )== JIM_ERR ){
+ Jim_FreeNewObj(interp, resObjPtr );
+ return NULL;
+ }
+ width = wideValue;
+ if( width < 0 ){
+ ljust = 1;
+ width = -width;
+ }
+ objv++;
+ goto next_fmt;
+ break;
+ }
+
+
+ if (*fmt != '%') {
if (objc == 0) {
+ not_enough_args:
Jim_FreeNewObj(interp, resObjPtr);
Jim_SetResultString(interp,
- "not enough arguments for all format specifiers", -1);
+ "not
enough arguments for all format specifiers", -1);
return NULL;
} else {
objc--;
}
}
+
+ /*
+ * Create the formatter
+ * cause we cheat and use sprintf()
+ */
+ cp = fmt_str;
+ *cp++ = '%';
+ if( altfm ){
+ *cp++ = '#';
+ }
+ if( forceplus ){
+ *cp++ = '+';
+ } else if( spad ){
+ /* PLUS overrides */
+ *cp++ = ' ';
+ }
+ if( ljust ){
+ *cp++ = '-';
+ }
+ if( zpad ){
+ *cp++ = '0';
+ }
+ if( width > 0 ){
+ sprintf( cp, "%d", width );
+ /* skip ahead */
+ cp = strchr(cp,0);
+ }
+ *cp = 0;
+
+ /* here we do the work */
+ /* actually - we make sprintf() do it for us */
switch(*fmt) {
case 's':
- Jim_AppendObj(interp, resObjPtr, objv[0]);
- objv++;
+ *cp++ = 's';
+ *cp = 0;
+ /* BUG: we do not handled embeded NULLs */
+ snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str,
Jim_GetString( objv[0], NULL ));
break;
case 'c':
+ *cp++ = 'c';
+ *cp = 0;
if (Jim_GetWide(interp, objv[0], &wideValue) == JIM_ERR) {
Jim_FreeNewObj(interp, resObjPtr);
return NULL;
}
c = (char) wideValue;
- Jim_AppendString(interp, resObjPtr, &c, 1);
+ snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str, c );
break;
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ case 'e':
+ case 'E':
+ *cp++ = *fmt;
+ *cp = 0;
+ if( Jim_GetDouble( interp, objv[0], &doubleValue ) ==
JIM_ERR ){
+ Jim_FreeNewObj( interp, resObjPtr );
+ return NULL;
+ }
+ snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str,
doubleValue );
+ break;
case 'd':
+ case 'i':
+ case 'u':
+ case 'x':
+ case 'X':
+ /* jim widevaluse are 64bit */
+ if( sizeof(jim_wide) == sizeof(long long) ){
+ *cp++ = 'l';
+ *cp++ = 'l';
+ } else {
+ *cp++ = 'l';
+ }
+ *cp++ = *fmt;
+ *cp = 0;
if (Jim_GetWide(interp, objv[0], &wideValue) == JIM_ERR) {
Jim_FreeNewObj(interp, resObjPtr);
return NULL;
}
- Jim_AppendObj(interp, resObjPtr, objv[0]);
+ snprintf(sprintf_buf, JIM_MAX_FMT, fmt_str, wideValue );
break;
case '%':
- Jim_AppendString(interp, resObjPtr, "%" , 1);
+ sprintf_buf[0] = '%';
+ sprintf_buf[1] = 0;
+ objv--; /* undo the objv++ below */
break;
default:
spec[0] = *fmt; spec[1] = '\0';
@@ -2200,6 +2366,16 @@
"bad field specifier \"", spec, "\"", NULL);
return NULL;
}
+ /* force terminate */
+#if 0
+ printf("FMT was: %s\n", fmt_str );
+ printf("RES was: |%s|\n", sprintf_buf );
+#endif
+
+ sprintf_buf[ JIM_MAX_FMT - 1] = 0;
+ Jim_AppendString( interp, resObjPtr, sprintf_buf,
strlen(sprintf_buf) );
+ /* next obj */
+ objv++;
fmt++;
fmtLen--;
}
@@ -11827,3 +12003,11 @@
out:
return 0;
}
+
+/*
+ * Local Variables: **
+ * tab-width: 4 **
+ * c-basic-offset: 4 **
+ * End: **
+ */
+
# test case 0
format "%d %d %d" 12 34 56
# ERROR - Old version shows 12 12 12
format "A%10dB" 12
format "A%-10dB" 12
format "A%+10dB" 12
# Right just, with0 fill
format "A%+010dB" 12
format "A%-010dB" 12
# Floating point variations
format "A%+010fB" 12.34
format "A%-010FB" 12.34
format "A%+010eB" 12.34
format "A%-010EB" 12.34
format "A%-010gB" 12.34
format "A% 010GB" -12.34
format "A%+010fB" -12.34
format "A%-010FB" -12.34
format "A%+010eB" -12.34
format "A%-010EB" -12.34
format "A%-010gB" -12.34
format "A% 010GB" -12.34
# Supporting the * specifier
format "A%sB - A%*sB A%sB" dog 20 cat frog
# Supporting the NEGATIVE * specifier
format "A%sB - A%*sB A%sB" dog -20 cat frog
# hex format
format "A%xB |0x%08x|" 12 0xdeadbeef
format "A%XB |0x%08X|" 12 0xdefeca8d
format "A%xB |0x%08x|" 12 0xdeadbeef
for { set x 0x40 } { $x < 0x5f } { incr x } { puts [format "chr 0x%02x => %c
" $x $x] }
puts "DONE WITH FOR"
#Try the following command:
#
# % format "x%1000dz" 123]
#
#The debug output is correct, the output to TELNET is wrong.
#
#WORK AROUND:
# Format strings must be <= 100 (or so chars)
#----------------------------------------
# THIS still crashes JIM..
#----------------------------------------
#for { set x 0 } { $x < 0x5f } { incr x } { puts "Hi $x" }
puts "DONE DONE DONE"
_______________________________________________
Openocd-development mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/openocd-development