debuggers: import openocd-0.7.0
Initial check-in of openocd-0.7.0 as it can be downloaded from http://sourceforge.net/projects/openocd/files/openocd/0.7.0/ Any modifications will follow. Change-Id: I6949beaefd589e046395ea0cb80f4e1ab1654d55
This commit is contained in:
432
debuggers/openocd/jimtcl/jim-format.c
Normal file
432
debuggers/openocd/jimtcl/jim-format.c
Normal file
@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Implements the internals of the format command for jim
|
||||
*
|
||||
* The FreeBSD license
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* official policies, either expressed or implied, of the Jim Tcl Project.
|
||||
*
|
||||
* Based on code originally from Tcl 8.5:
|
||||
*
|
||||
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
|
||||
* Copyright (c) 1999 by Scriptics Corporation.
|
||||
*
|
||||
* See the file "tcl.license.terms" for information on usage and redistribution of
|
||||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <jim.h>
|
||||
#include "utf8.h"
|
||||
|
||||
#define JIM_UTF_MAX 3
|
||||
#define JIM_INTEGER_SPACE 24
|
||||
#define MAX_FLOAT_WIDTH 320
|
||||
|
||||
/**
|
||||
* Apply the printf-like format in fmtObjPtr with the given arguments.
|
||||
*
|
||||
* Returns a new object with zero reference count if OK, or NULL on error.
|
||||
*/
|
||||
Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
|
||||
{
|
||||
const char *span, *format, *formatEnd, *msg;
|
||||
int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
|
||||
static const char * const mixedXPG =
|
||||
"cannot mix \"%\" and \"%n$\" conversion specifiers";
|
||||
static const char * const badIndex[2] = {
|
||||
"not enough arguments for all format specifiers",
|
||||
"\"%n$\" argument index out of range"
|
||||
};
|
||||
int formatLen;
|
||||
Jim_Obj *resultPtr;
|
||||
|
||||
/* A single buffer is used to store numeric fields (with sprintf())
|
||||
* This buffer is allocated/reallocated as necessary
|
||||
*/
|
||||
char *num_buffer = NULL;
|
||||
int num_buffer_size = 0;
|
||||
|
||||
span = format = Jim_GetString(fmtObjPtr, &formatLen);
|
||||
formatEnd = format + formatLen;
|
||||
resultPtr = Jim_NewStringObj(interp, "", 0);
|
||||
|
||||
while (format != formatEnd) {
|
||||
char *end;
|
||||
int gotMinus, sawFlag;
|
||||
int gotPrecision, useShort;
|
||||
long width, precision;
|
||||
int newXpg;
|
||||
int ch;
|
||||
int step;
|
||||
int doubleType;
|
||||
char pad = ' ';
|
||||
char spec[2*JIM_INTEGER_SPACE + 12];
|
||||
char *p;
|
||||
|
||||
int formatted_chars;
|
||||
int formatted_bytes;
|
||||
const char *formatted_buf;
|
||||
|
||||
step = utf8_tounicode(format, &ch);
|
||||
format += step;
|
||||
if (ch != '%') {
|
||||
numBytes += step;
|
||||
continue;
|
||||
}
|
||||
if (numBytes) {
|
||||
Jim_AppendString(interp, resultPtr, span, numBytes);
|
||||
numBytes = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Saw a % : process the format specifier.
|
||||
*
|
||||
* Step 0. Handle special case of escaped format marker (i.e., %%).
|
||||
*/
|
||||
|
||||
step = utf8_tounicode(format, &ch);
|
||||
if (ch == '%') {
|
||||
span = format;
|
||||
numBytes = step;
|
||||
format += step;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 1. XPG3 position specifier
|
||||
*/
|
||||
|
||||
newXpg = 0;
|
||||
if (isdigit(ch)) {
|
||||
int position = strtoul(format, &end, 10);
|
||||
if (*end == '$') {
|
||||
newXpg = 1;
|
||||
objIndex = position - 1;
|
||||
format = end + 1;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
}
|
||||
}
|
||||
if (newXpg) {
|
||||
if (gotSequential) {
|
||||
msg = mixedXPG;
|
||||
goto errorMsg;
|
||||
}
|
||||
gotXpg = 1;
|
||||
} else {
|
||||
if (gotXpg) {
|
||||
msg = mixedXPG;
|
||||
goto errorMsg;
|
||||
}
|
||||
gotSequential = 1;
|
||||
}
|
||||
if ((objIndex < 0) || (objIndex >= objc)) {
|
||||
msg = badIndex[gotXpg];
|
||||
goto errorMsg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 2. Set of flags. Also build up the sprintf spec.
|
||||
*/
|
||||
p = spec;
|
||||
*p++ = '%';
|
||||
|
||||
gotMinus = 0;
|
||||
sawFlag = 1;
|
||||
do {
|
||||
switch (ch) {
|
||||
case '-':
|
||||
gotMinus = 1;
|
||||
break;
|
||||
case '0':
|
||||
pad = ch;
|
||||
break;
|
||||
case ' ':
|
||||
case '+':
|
||||
case '#':
|
||||
break;
|
||||
default:
|
||||
sawFlag = 0;
|
||||
continue;
|
||||
}
|
||||
*p++ = ch;
|
||||
format += step;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
} while (sawFlag);
|
||||
|
||||
/*
|
||||
* Step 3. Minimum field width.
|
||||
*/
|
||||
|
||||
width = 0;
|
||||
if (isdigit(ch)) {
|
||||
width = strtoul(format, &end, 10);
|
||||
format = end;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
} else if (ch == '*') {
|
||||
if (objIndex >= objc - 1) {
|
||||
msg = badIndex[gotXpg];
|
||||
goto errorMsg;
|
||||
}
|
||||
if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
|
||||
goto error;
|
||||
}
|
||||
if (width < 0) {
|
||||
width = -width;
|
||||
if (!gotMinus) {
|
||||
*p++ = '-';
|
||||
gotMinus = 1;
|
||||
}
|
||||
}
|
||||
objIndex++;
|
||||
format += step;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 4. Precision.
|
||||
*/
|
||||
|
||||
gotPrecision = precision = 0;
|
||||
if (ch == '.') {
|
||||
gotPrecision = 1;
|
||||
format += step;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
}
|
||||
if (isdigit(ch)) {
|
||||
precision = strtoul(format, &end, 10);
|
||||
format = end;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
} else if (ch == '*') {
|
||||
if (objIndex >= objc - 1) {
|
||||
msg = badIndex[gotXpg];
|
||||
goto errorMsg;
|
||||
}
|
||||
if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Check this truncation logic.
|
||||
*/
|
||||
|
||||
if (precision < 0) {
|
||||
precision = 0;
|
||||
}
|
||||
objIndex++;
|
||||
format += step;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 5. Length modifier.
|
||||
*/
|
||||
|
||||
useShort = 0;
|
||||
if (ch == 'h') {
|
||||
useShort = 1;
|
||||
format += step;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
} else if (ch == 'l') {
|
||||
/* Just for compatibility. All non-short integers are wide. */
|
||||
format += step;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
if (ch == 'l') {
|
||||
format += step;
|
||||
step = utf8_tounicode(format, &ch);
|
||||
}
|
||||
}
|
||||
|
||||
format += step;
|
||||
span = format;
|
||||
|
||||
/*
|
||||
* Step 6. The actual conversion character.
|
||||
*/
|
||||
|
||||
if (ch == 'i') {
|
||||
ch = 'd';
|
||||
}
|
||||
|
||||
doubleType = 0;
|
||||
|
||||
/* Each valid conversion will set:
|
||||
* formatted_buf - the result to be added
|
||||
* formatted_chars - the length of formatted_buf in characters
|
||||
* formatted_bytes - the length of formatted_buf in bytes
|
||||
*/
|
||||
switch (ch) {
|
||||
case '\0':
|
||||
msg = "format string ended in middle of field specifier";
|
||||
goto errorMsg;
|
||||
case 's': {
|
||||
formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
|
||||
formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
|
||||
if (gotPrecision && (precision < formatted_chars)) {
|
||||
/* Need to build a (null terminated) truncated string */
|
||||
formatted_chars = precision;
|
||||
formatted_bytes = utf8_index(formatted_buf, precision);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
jim_wide code;
|
||||
|
||||
if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
|
||||
goto error;
|
||||
}
|
||||
/* Just store the value in the 'spec' buffer */
|
||||
formatted_bytes = utf8_fromunicode(spec, code);
|
||||
formatted_buf = spec;
|
||||
formatted_chars = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G':
|
||||
doubleType = 1;
|
||||
/* fall through */
|
||||
case 'd':
|
||||
case 'u':
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'X': {
|
||||
jim_wide w;
|
||||
double d;
|
||||
int length;
|
||||
|
||||
/* Fill in the width and precision */
|
||||
if (width) {
|
||||
p += sprintf(p, "%ld", width);
|
||||
}
|
||||
if (gotPrecision) {
|
||||
p += sprintf(p, ".%ld", precision);
|
||||
}
|
||||
|
||||
/* Now the modifier, and get the actual value here */
|
||||
if (doubleType) {
|
||||
if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
|
||||
goto error;
|
||||
}
|
||||
length = MAX_FLOAT_WIDTH;
|
||||
}
|
||||
else {
|
||||
if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
|
||||
goto error;
|
||||
}
|
||||
length = JIM_INTEGER_SPACE;
|
||||
if (useShort) {
|
||||
*p++ = 'h';
|
||||
if (ch == 'd') {
|
||||
w = (short)w;
|
||||
}
|
||||
else {
|
||||
w = (unsigned short)w;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*p++ = 'l';
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (sizeof(long long) == sizeof(jim_wide)) {
|
||||
*p++ = 'l';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
*p++ = (char) ch;
|
||||
*p = '\0';
|
||||
|
||||
/* Adjust length for width and precision */
|
||||
if (width > length) {
|
||||
length = width;
|
||||
}
|
||||
if (gotPrecision) {
|
||||
length += precision;
|
||||
}
|
||||
|
||||
/* Increase the size of the buffer if needed */
|
||||
if (num_buffer_size < length + 1) {
|
||||
num_buffer_size = length + 1;
|
||||
num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
|
||||
}
|
||||
|
||||
if (doubleType) {
|
||||
snprintf(num_buffer, length + 1, spec, d);
|
||||
}
|
||||
else {
|
||||
formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
|
||||
}
|
||||
formatted_chars = formatted_bytes = strlen(num_buffer);
|
||||
formatted_buf = num_buffer;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
/* Just reuse the 'spec' buffer */
|
||||
spec[0] = ch;
|
||||
spec[1] = '\0';
|
||||
Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gotMinus) {
|
||||
while (formatted_chars < width) {
|
||||
Jim_AppendString(interp, resultPtr, &pad, 1);
|
||||
formatted_chars++;
|
||||
}
|
||||
}
|
||||
|
||||
Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
|
||||
|
||||
while (formatted_chars < width) {
|
||||
Jim_AppendString(interp, resultPtr, &pad, 1);
|
||||
formatted_chars++;
|
||||
}
|
||||
|
||||
objIndex += gotSequential;
|
||||
}
|
||||
if (numBytes) {
|
||||
Jim_AppendString(interp, resultPtr, span, numBytes);
|
||||
}
|
||||
|
||||
Jim_Free(num_buffer);
|
||||
return resultPtr;
|
||||
|
||||
errorMsg:
|
||||
Jim_SetResultString(interp, msg, -1);
|
||||
error:
|
||||
Jim_FreeNewObj(interp, resultPtr);
|
||||
Jim_Free(num_buffer);
|
||||
return NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user