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

Reply via email to