Remodel logic of the size that integer items occupy in terminal write
Integers can be hexadecimal, decimal or octal. An optional case-insensitive suffix specifies their size: HH: 8 bit, H/S: 16 bit, L: 32 bit, LL: 64 bit An optional U suffix makes a number unsigned. Ordinary 0x hex numbers are always treated as unsigned. +0x or -0x hex numbers are treated as signed unless they have a U suffix. Unsigned integers cannot be larger than 2^64-1. If n is an unsigned integer then -n is also a valid unsigned integer as in C. Signed integers must fall into the [-2^63, 2^63-1] range or a correspondingly smaller range when a suffix specifies a smaller type. Out of range signed numbers trigger a warning. Ordinary 0x hex numbers with n hex digits (counting leading zeros) use the smallest size of 1, 2, 4 and 8 bytes that can accommodate any n-digit hex number. If a suffix specifies a size explicitly the corresponding number of least significant bytes are written. Otherwise, signed and unsigned integers alike occupy the smallest of 1, 2, 4, or 8 bytes needed to accommodate them in their respective representation.
This commit is contained in:
parent
62d3eebd56
commit
51355d04fb
141
src/term.c
141
src/term.c
|
@ -419,6 +419,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
|
||||||
union {
|
union {
|
||||||
float f;
|
float f;
|
||||||
int64_t ll;
|
int64_t ll;
|
||||||
|
uint64_t ull;
|
||||||
uint8_t a[8];
|
uint8_t a[8];
|
||||||
};
|
};
|
||||||
} data = {
|
} data = {
|
||||||
|
@ -444,44 +445,99 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
|
||||||
data.str_ptr = NULL;
|
data.str_ptr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get suffix if present
|
// Try integers and assign data size
|
||||||
char suffix = 0, lsuffix = 0;
|
errno = 0;
|
||||||
if(arglen > 1) {
|
data.ull = strtoull(argi, &end_ptr, 0);
|
||||||
suffix = toupper(argi[arglen - 1]);
|
if (!(end_ptr == argi || errno)) {
|
||||||
lsuffix = toupper(argi[arglen - 2]);
|
unsigned int nu=0, nl=0, nh=0, ns=0, nx=0;
|
||||||
if (suffix == 'L' && lsuffix == 'L') {
|
char *p;
|
||||||
argi[arglen -= 2] = '\0';
|
|
||||||
data.size = 8;
|
// parse suffixes: ULL, LL, UL, L ... UHH, HH
|
||||||
} else if (suffix == 'L' || suffix == 'l') {
|
for(p=end_ptr; *p; p++)
|
||||||
argi[--arglen] = '\0';
|
switch(toupper(*p)) {
|
||||||
data.size = 4;
|
case 'U': nu++; break;
|
||||||
} else if ((suffix == 'F') &&
|
case 'L': nl++; break;
|
||||||
strncmp(argi, "0x", 2) && strncmp(argi, "-0x", 3) && strncmp(argi, "+0x", 3)) {
|
case 'H': nh++; break;
|
||||||
argi[--arglen] = '\0';
|
case 'S': ns++; break;
|
||||||
data.size = 4;
|
default: nx++;
|
||||||
} else if (suffix == 'H' && lsuffix == 'H') {
|
}
|
||||||
argi[arglen -= 2] = '\0';
|
|
||||||
|
if(nx==0 && nu<2 && nl<3 && nh<3 && ns<2) { // could be valid integer suffix
|
||||||
|
if(nu==0 || toupper(*end_ptr) == 'U' || toupper(p[-1]) == 'U') { // if U, then must be at start or end
|
||||||
|
bool is_hex = strncasecmp(argi, "0x", 2) == 0; // ordinary hex: "0x..." without explicit +/- sign
|
||||||
|
bool is_signed = !(nu || is_hex); // neither explicitly unsigned nor ordinary hex
|
||||||
|
bool is_outside_int64_t = 0;
|
||||||
|
bool is_out_of_range = 0;
|
||||||
|
int nhexdigs = p-argi-2;
|
||||||
|
|
||||||
|
if(is_signed) { // Is input in range for int64_t?
|
||||||
|
errno = 0; (void) strtoll(argi, NULL, 0);
|
||||||
|
is_outside_int64_t = errno == ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nl==0 && ns==0 && nh==0) { // no explicit data size
|
||||||
|
// ordinary hex numbers have "implicit" size, given by number of hex digits, including leading zeros
|
||||||
|
if(is_hex) {
|
||||||
|
data.size = nhexdigs > 8? 8: nhexdigs > 4? 4: nhexdigs > 2? 2: 1;
|
||||||
|
|
||||||
|
} else if(is_signed) {
|
||||||
|
// smallest size that fits signed representation
|
||||||
|
data.size =
|
||||||
|
is_outside_int64_t? 8:
|
||||||
|
data.ll < INT32_MIN || data.ll > INT32_MAX? 8:
|
||||||
|
data.ll < INT16_MIN || data.ll > INT16_MAX? 4:
|
||||||
|
data.ll < INT8_MIN || data.ll > INT8_MAX? 2: 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// smallest size that fits unsigned representation
|
||||||
|
data.size =
|
||||||
|
data.ull > UINT32_MAX? 8:
|
||||||
|
data.ull > UINT16_MAX? 4:
|
||||||
|
data.ull > UINT8_MAX? 2: 1;
|
||||||
|
}
|
||||||
|
} else if(nl==0 && nh==2 && ns==0) { // HH
|
||||||
data.size = 1;
|
data.size = 1;
|
||||||
} else if (suffix == 'H' || suffix == 'S') {
|
if(is_outside_int64_t || (is_signed && (data.ll < INT8_MIN || data.ll > INT8_MAX))) {
|
||||||
argi[--arglen] = '\0';
|
is_out_of_range = 1;
|
||||||
|
data.ll = (int8_t) data.ll;
|
||||||
|
}
|
||||||
|
} else if(nl==0 && ((nh==1 && ns==0) || (nh==0 && ns==1))) { // H or S
|
||||||
data.size = 2;
|
data.size = 2;
|
||||||
} else if (suffix == '\'') {
|
if(is_outside_int64_t || (is_signed && (data.ll < INT16_MIN || data.ll > INT16_MAX))) {
|
||||||
data.size = 1;
|
is_out_of_range = 1;
|
||||||
|
data.ll = (int16_t) data.ll;
|
||||||
|
}
|
||||||
|
} else if(nl==1 && nh==0 && ns==0) { // L
|
||||||
|
data.size = 4;
|
||||||
|
if(is_outside_int64_t || (is_signed && (data.ll < INT32_MIN || data.ll > INT32_MAX))) {
|
||||||
|
is_out_of_range = 1;
|
||||||
|
data.ll = (int32_t) data.ll;
|
||||||
|
}
|
||||||
|
} else if(nl==2 && nh==0 && ns==0) { // LL
|
||||||
|
data.size = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_outside_int64_t || is_out_of_range)
|
||||||
|
avrdude_message(MSG_INFO, "%s (write): %s out of int%d_t range, "
|
||||||
|
"interpreted as %d-byte %lld%s; consider 'U' suffix\n",
|
||||||
|
progname, argi, data.size*8, data.size, data.ll,
|
||||||
|
is_out_of_range? " (unlikely what you want)": ""
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try integers
|
if(!data.size) { // Data item was not recognised as integer
|
||||||
errno = 0;
|
|
||||||
data.ll = strtoull(argi, &end_ptr, 0);
|
|
||||||
if (!(end_ptr == argi || errno)) {
|
|
||||||
// Try float
|
// Try float
|
||||||
data.f = strtof(argi, &end_ptr);
|
data.f = strtof(argi, &end_ptr);
|
||||||
|
if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) {
|
||||||
data.is_float = true;
|
data.is_float = true;
|
||||||
if (*end_ptr || (end_ptr == argi)) {
|
data.size = 4;
|
||||||
data.is_float = false;
|
} else {
|
||||||
// Try single character
|
// Try single character
|
||||||
if (argi[0] == '\'' && argi[2] == '\'') {
|
if (argi[0] == '\'' && argi[2] == '\'') {
|
||||||
data.ll = argi[1];
|
data.ll = argi[1];
|
||||||
|
data.size = 1;
|
||||||
} else {
|
} else {
|
||||||
// Try string that starts and ends with quotes
|
// Try string that starts and ends with quotes
|
||||||
if (argi[0] == '\"' && argi[arglen - 1] == '\"') {
|
if (argi[0] == '\"' && argi[arglen - 1] == '\"') {
|
||||||
|
@ -503,35 +559,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print warning if data size might be ambiguous
|
|
||||||
bool is_hex = (strncmp(argi, "0x", 2) == 0);
|
|
||||||
bool is_neg_hex = (strncmp(argi, "-0x", 3) == 0);
|
|
||||||
bool leading_zero = (strncmp(argi, "0x0", 3) == 0);
|
|
||||||
int8_t hex_digits = (arglen - 2);
|
|
||||||
if(!data.size // No pre-defined size
|
|
||||||
&& (is_neg_hex // Hex with - sign in front
|
|
||||||
|| (is_hex && leading_zero && (hex_digits & (hex_digits - 1))) // Hex with 3, 5, 6 or 7 digits
|
|
||||||
|| (!is_hex && !data.is_float && llabs(data.ll) > 0xFF && arglen > 2))) // Base10 int greater than 255
|
|
||||||
{
|
|
||||||
avrdude_message(MSG_INFO, "Warning: no size suffix specified for \"%s\". "
|
|
||||||
"Writing %d byte(s)\n",
|
|
||||||
argi,
|
|
||||||
llabs(data.ll) > UINT32_MAX ? 8 :
|
|
||||||
llabs(data.ll) > UINT16_MAX || data.is_float ? 4 : \
|
|
||||||
llabs(data.ll) > UINT8_MAX ? 2 : 1);
|
|
||||||
}
|
|
||||||
// Adjust size if signed integer
|
|
||||||
if (data.ll < 0 && !data.is_float) {
|
|
||||||
if (data.ll < INT32_MIN)
|
|
||||||
data.size = 8;
|
|
||||||
else if (data.ll < INT16_MIN)
|
|
||||||
data.size = 4;
|
|
||||||
else if (data.ll < INT8_MIN)
|
|
||||||
data.size = 2;
|
|
||||||
else
|
|
||||||
data.size = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(data.str_ptr) {
|
if(data.str_ptr) {
|
||||||
for(int16_t j = 0; j < strlen(data.str_ptr); j++)
|
for(int16_t j = 0; j < strlen(data.str_ptr); j++)
|
||||||
|
@ -1175,5 +1202,3 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p)
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue