From d9450058c8667d9d3fe5ce467210305d93ad1159 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:12:20 +0100 Subject: [PATCH 01/38] Cache strlen(argv[i]) in term.c cmd_write() and prevent negative array index --- src/term.c | 84 +++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/src/term.c b/src/term.c index dc771273..1ddaf885 100644 --- a/src/term.c +++ b/src/term.c @@ -426,6 +426,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Handle the next argument if (i < argc - start_offset + 3) { + char *argi = argv[i]; + size_t arglen = strlen(argi); + // Free string pointer if already allocated if(data.str_ptr) { free(data.str_ptr); @@ -433,52 +436,55 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Get suffix if present - char suffix = argv[i][strlen(argv[i]) - 1]; - char lsuffix = argv[i][strlen(argv[i]) - 2]; - if ((suffix == 'L' && lsuffix == 'L') || (suffix == 'l' && lsuffix == 'l')) { - argv[i][strlen(argv[i]) - 2] = '\0'; - data.size = 8; - } else if (suffix == 'L' || suffix == 'l') { - argv[i][strlen(argv[i]) - 1] = '\0'; - data.size = 4; - } else if ((suffix == 'F' || suffix == 'f') && - strncmp(argv[i], "0x", 2) != 0 && strncmp(argv[i], "-0x", 3) != 0) { - argv[i][strlen(argv[i]) - 1] = '\0'; - data.size = 4; - } else if ((suffix == 'H' && lsuffix == 'H') || (suffix == 'h' && lsuffix == 'h')) { - argv[i][strlen(argv[i]) - 2] = '\0'; - data.size = 1; - } else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') { - argv[i][strlen(argv[i]) - 1] = '\0'; - data.size = 2; - } else if (suffix == '\'') { - data.size = 1; + char suffix = 0, lsuffix = 0; + if(arglen > 1) { + suffix = argi[arglen - 1]; + lsuffix = argi[arglen - 2]; + if ((suffix == 'L' && lsuffix == 'L') || (suffix == 'l' && lsuffix == 'l')) { + argi[arglen -= 2] = '\0'; + data.size = 8; + } else if (suffix == 'L' || suffix == 'l') { + argi[--arglen] = '\0'; + data.size = 4; + } else if ((suffix == 'F' || suffix == 'f') && + strncmp(argi, "0x", 2) != 0 && strncmp(argi, "-0x", 3) != 0) { + argi[--arglen] = '\0'; + data.size = 4; + } else if ((suffix == 'H' && lsuffix == 'H') || (suffix == 'h' && lsuffix == 'h')) { + argi[arglen -= 2] = '\0'; + data.size = 1; + } else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') { + argi[--arglen] = '\0'; + data.size = 2; + } else if (suffix == '\'') { + data.size = 1; + } } // Try integers - data.ll = strtoll(argv[i], &end_ptr, 0); - if (*end_ptr || (end_ptr == argv[i])) { + data.ll = strtoll(argi, &end_ptr, 0); + if (*end_ptr || (end_ptr == argi)) { // Try float - data.f = strtof(argv[i], &end_ptr); + data.f = strtof(argi, &end_ptr); data.is_float = true; - if (*end_ptr || (end_ptr == argv[i])) { + if (*end_ptr || (end_ptr == argi)) { data.is_float = false; // Try single character - if (argv[i][0] == '\'' && argv[i][2] == '\'') { - data.ll = argv[i][1]; + if (argi[0] == '\'' && argi[2] == '\'') { + data.ll = argi[1]; } else { // Try string that starts and ends with quotes - if (argv[i][0] == '\"' && argv[i][strlen(argv[i]) - 1] == '\"') { - data.str_ptr = calloc(strlen(argv[i]), sizeof(char)); + if (argi[0] == '\"' && argi[arglen - 1] == '\"') { + data.str_ptr = calloc(arglen, sizeof(char)); if (data.str_ptr == NULL) { avrdude_message(MSG_INFO, "%s (write str): out of memory\n", progname); return -1; } // Strip start and end quotes - strncpy(data.str_ptr, argv[i] + 1, strlen(argv[i]) - 2); + strncpy(data.str_ptr, argi + 1, arglen - 2); } else { avrdude_message(MSG_INFO, "\n%s (write): can't parse data '%s'\n", - progname, argv[i]); + progname, argi); free(buf); if(data.str_ptr != NULL) free(data.str_ptr); @@ -489,18 +495,18 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Print warning if data size might be ambiguous - bool is_hex = (strncmp(argv[i], "0x", 2) == 0); - bool is_neg_hex = (strncmp(argv[i], "-0x", 3) == 0); - bool leading_zero = (strncmp(argv[i], "0x0", 3) == 0); - int8_t hex_digits = (strlen(argv[i]) - 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 && strlen(argv[i]) > 2))) // Base10 int greater than 255 + 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", - argv[i], + argi, llabs(data.ll) > UINT32_MAX ? 8 : llabs(data.ll) > UINT16_MAX || data.is_float ? 4 : \ llabs(data.ll) > UINT8_MAX ? 2 : 1); From 360d7c502b69920124d6eb51c39ec08951274363 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:13:46 +0100 Subject: [PATCH 02/38] Make suffix fully case insensitive (allow Hh, Ll, ...) in terminal write --- src/term.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/term.c b/src/term.c index 1ddaf885..534cf67b 100644 --- a/src/term.c +++ b/src/term.c @@ -438,22 +438,22 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Get suffix if present char suffix = 0, lsuffix = 0; if(arglen > 1) { - suffix = argi[arglen - 1]; - lsuffix = argi[arglen - 2]; - if ((suffix == 'L' && lsuffix == 'L') || (suffix == 'l' && lsuffix == 'l')) { + suffix = toupper(argi[arglen - 1]); + lsuffix = toupper(argi[arglen - 2]); + if (suffix == 'L' && lsuffix == 'L') { argi[arglen -= 2] = '\0'; data.size = 8; } else if (suffix == 'L' || suffix == 'l') { argi[--arglen] = '\0'; data.size = 4; - } else if ((suffix == 'F' || suffix == 'f') && + } else if ((suffix == 'F') && strncmp(argi, "0x", 2) != 0 && strncmp(argi, "-0x", 3) != 0) { argi[--arglen] = '\0'; data.size = 4; - } else if ((suffix == 'H' && lsuffix == 'H') || (suffix == 'h' && lsuffix == 'h')) { + } else if (suffix == 'H' && lsuffix == 'H') { argi[arglen -= 2] = '\0'; data.size = 1; - } else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') { + } else if (suffix == 'H' || suffix == 'S') { argi[--arglen] = '\0'; data.size = 2; } else if (suffix == '\'') { From 39a00bc71ed2527ad1953f1465df22f4961c6d5a Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:14:41 +0100 Subject: [PATCH 03/38] Ensure +0x...f does not strip suffix f in terminal write --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 534cf67b..ce6c6157 100644 --- a/src/term.c +++ b/src/term.c @@ -447,7 +447,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, argi[--arglen] = '\0'; data.size = 4; } else if ((suffix == 'F') && - strncmp(argi, "0x", 2) != 0 && strncmp(argi, "-0x", 3) != 0) { + strncmp(argi, "0x", 2) && strncmp(argi, "-0x", 3) && strncmp(argi, "+0x", 3)) { argi[--arglen] = '\0'; data.size = 4; } else if (suffix == 'H' && lsuffix == 'H') { From d3ad078577b07833e0a40be32f84e7850ff4898b Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:15:30 +0100 Subject: [PATCH 04/38] Ensure terminal write fill mode ... always fills with last data item --- src/term.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/term.c b/src/term.c index ce6c6157..881207fc 100644 --- a/src/term.c +++ b/src/term.c @@ -421,14 +421,14 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, }; for (i = start_offset; i < len + start_offset; i++) { - data.is_float = false; - data.size = 0; - // Handle the next argument if (i < argc - start_offset + 3) { char *argi = argv[i]; size_t arglen = strlen(argi); + data.is_float = false; + data.size = 0; + // Free string pointer if already allocated if(data.str_ptr) { free(data.str_ptr); From 177834ae7c72bc0738af41dc32cd3b0dfb14fdb7 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:16:16 +0100 Subject: [PATCH 05/38] Ensure enough memory is allocated for buf in terminal write --- src/term.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 881207fc..64bee430 100644 --- a/src/term.c +++ b/src/term.c @@ -334,6 +334,16 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } +static size_t maxstrlen(int argc, char **argv) { + size_t max = 0; + + for(int i=0; i max) + max = strlen(argv[i]); + + return max; +} + static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { @@ -374,7 +384,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Allocate a buffer guaranteed to be large enough - uint8_t * buf = calloc(mem->size + 0x10 + strlen(argv[argc - 2]), sizeof(uint8_t)); + uint8_t * buf = calloc(mem->size + 0x10 + maxstrlen(argc-3, argv+3), sizeof(uint8_t)); if (buf == NULL) { avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname); return -1; From ff43e0544d40e70bc911f5a85090f1c354e6b2f9 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:18:15 +0100 Subject: [PATCH 06/38] Correct a parse message in terminal write --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 64bee430..7e635463 100644 --- a/src/term.c +++ b/src/term.c @@ -396,7 +396,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, start_offset = 4; len = strtoul(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (write ...): can't parse address \"%s\"\n", + avrdude_message(MSG_INFO, "%s (write ...): can't parse length \"%s\"\n", progname, argv[3]); free(buf); return -1; From 9afa56381e2c60158f84ccdcbe9789120815317d Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:19:05 +0100 Subject: [PATCH 07/38] Remove unused component is_signed in terminal write --- src/term.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/term.c b/src/term.c index 7e635463..ac36e3bf 100644 --- a/src/term.c +++ b/src/term.c @@ -413,7 +413,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int32_t bytes_grown; uint8_t size; bool is_float; - bool is_signed; char * str_ptr; // Data union union { @@ -425,7 +424,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, .bytes_grown = 0, .size = 0, .is_float = false, - .is_signed = false, .str_ptr = NULL, .ll = 0 }; @@ -521,9 +519,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, llabs(data.ll) > UINT16_MAX || data.is_float ? 4 : \ llabs(data.ll) > UINT8_MAX ? 2 : 1); } - // Flag if signed integer and adjust size + // Adjust size if signed integer if (data.ll < 0 && !data.is_float) { - data.is_signed = true; if (data.ll < INT32_MIN) data.size = 8; else if (data.ll < INT16_MIN) From 62d3eebd568c2078428a55485675a8411d97f415 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:19:47 +0100 Subject: [PATCH 08/38] Fix 64-bit integer terminal write where high bit set Using strtoll() can only return numbers in the range [-2^63, 2^63-1]. This means that 0xffffFFFFffffFFFF (2^64-1) will be out of range and is written as max LL. Actually, every 64-bit number with high-bit set will wrongly be written as max LL. This commit uses strtoull() instead to fix this, and checks for unsiged out- of-range error. strtoull() also has the neat benefit that input with a minus sign is treated like C unsigned numbers, ie, -u is also a valid unsigned number if only u is one. In case the input is meant to be treated as signed, it is therefore still OK to use strtoull() in the first instance only that in this case a second check against the range of the signed domain is necessary. --- src/term.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/term.c b/src/term.c index ac36e3bf..203168de 100644 --- a/src/term.c +++ b/src/term.c @@ -26,6 +26,7 @@ #include #include #include +#include #if defined(HAVE_LIBREADLINE) # include @@ -470,8 +471,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Try integers - data.ll = strtoll(argi, &end_ptr, 0); - if (*end_ptr || (end_ptr == argi)) { + errno = 0; + data.ll = strtoull(argi, &end_ptr, 0); + if (!(end_ptr == argi || errno)) { // Try float data.f = strtof(argi, &end_ptr); data.is_float = true; From 51355d04fb34805a2b352475f01f13e8270f0822 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:32:38 +0100 Subject: [PATCH 09/38] 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. --- src/term.c | 157 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 91 insertions(+), 66 deletions(-) diff --git a/src/term.c b/src/term.c index 203168de..96ed8e57 100644 --- a/src/term.c +++ b/src/term.c @@ -419,6 +419,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, union { float f; int64_t ll; + uint64_t ull; uint8_t a[8]; }; } data = { @@ -444,44 +445,99 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.str_ptr = NULL; } - // Get suffix if present - char suffix = 0, lsuffix = 0; - if(arglen > 1) { - suffix = toupper(argi[arglen - 1]); - lsuffix = toupper(argi[arglen - 2]); - if (suffix == 'L' && lsuffix == 'L') { - argi[arglen -= 2] = '\0'; - data.size = 8; - } else if (suffix == 'L' || suffix == 'l') { - argi[--arglen] = '\0'; - data.size = 4; - } else if ((suffix == 'F') && - strncmp(argi, "0x", 2) && strncmp(argi, "-0x", 3) && strncmp(argi, "+0x", 3)) { - argi[--arglen] = '\0'; - data.size = 4; - } else if (suffix == 'H' && lsuffix == 'H') { - argi[arglen -= 2] = '\0'; - data.size = 1; - } else if (suffix == 'H' || suffix == 'S') { - argi[--arglen] = '\0'; - data.size = 2; - } else if (suffix == '\'') { - data.size = 1; + // Try integers and assign data size + errno = 0; + data.ull = strtoull(argi, &end_ptr, 0); + if (!(end_ptr == argi || errno)) { + unsigned int nu=0, nl=0, nh=0, ns=0, nx=0; + char *p; + + // parse suffixes: ULL, LL, UL, L ... UHH, HH + for(p=end_ptr; *p; p++) + switch(toupper(*p)) { + case 'U': nu++; break; + case 'L': nl++; break; + case 'H': nh++; break; + case 'S': ns++; break; + default: nx++; + } + + 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; + if(is_outside_int64_t || (is_signed && (data.ll < INT8_MIN || data.ll > INT8_MAX))) { + 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; + if(is_outside_int64_t || (is_signed && (data.ll < INT16_MIN || data.ll > INT16_MAX))) { + 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 - errno = 0; - data.ll = strtoull(argi, &end_ptr, 0); - if (!(end_ptr == argi || errno)) { + if(!data.size) { // Data item was not recognised as integer // Try float data.f = strtof(argi, &end_ptr); - data.is_float = true; - if (*end_ptr || (end_ptr == argi)) { - data.is_float = false; + if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) { + data.is_float = true; + data.size = 4; + } else { // Try single character if (argi[0] == '\'' && argi[2] == '\'') { data.ll = argi[1]; + data.size = 1; } else { // Try string that starts and ends with quotes 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) { for(int16_t j = 0; j < strlen(data.str_ptr); j++) @@ -912,7 +939,7 @@ static int cmd_help(PROGRAMMER * pgm, struct avrpart * p, fprintf(stdout, cmd[i].desc, cmd[i].name); fprintf(stdout, "\n"); } - fprintf(stdout, + fprintf(stdout, "\nUse the 'part' command to display valid memory types for use with the\n" "'dump' and 'write' commands.\n\n"); @@ -989,9 +1016,9 @@ static int tokenize(char * s, char *** argv) slen = strlen(s); - /* + /* * initialize allow for 20 arguments, use realloc to grow this if - * necessary + * necessary */ nargs = 20; bufsize = slen + 20; @@ -1047,7 +1074,7 @@ static int tokenize(char * s, char *** argv) } } - /* + /* * We have parsed all the args, n == argc, bufv contains an array of * pointers to each arg, and buf points to one memory block that * contains all the args, back to back, seperated by a nul @@ -1140,7 +1167,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) rc = 0; while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) { - /* + /* * find the start of the command, skipping any white space */ q = cmdbuf; @@ -1175,5 +1202,3 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return rc; } - - From feda75b60a20c3bfdc06af3c739e26c9c3b106c5 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:35:27 +0100 Subject: [PATCH 10/38] Remove unnecessary bool is_float in terminal write --- src/term.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/term.c b/src/term.c index 96ed8e57..7481f0ee 100644 --- a/src/term.c +++ b/src/term.c @@ -413,7 +413,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Data info int32_t bytes_grown; uint8_t size; - bool is_float; char * str_ptr; // Data union union { @@ -425,7 +424,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } data = { .bytes_grown = 0, .size = 0, - .is_float = false, .str_ptr = NULL, .ll = 0 }; @@ -436,7 +434,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char *argi = argv[i]; size_t arglen = strlen(argi); - data.is_float = false; data.size = 0; // Free string pointer if already allocated @@ -531,7 +528,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Try float data.f = strtof(argi, &end_ptr); if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) { - data.is_float = true; data.size = 4; } else { // Try single character @@ -565,9 +561,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, buf[i - start_offset + data.bytes_grown++] = (uint8_t)data.str_ptr[j]; } else { buf[i - start_offset + data.bytes_grown] = data.a[0]; - if (llabs(data.ll) > 0x000000FF || data.size >= 2 || data.is_float) + if (llabs(data.ll) > 0x000000FF || data.size >= 2) buf[i - start_offset + ++data.bytes_grown] = data.a[1]; - if (llabs(data.ll) > 0x0000FFFF || data.size >= 4 || data.is_float) { + if (llabs(data.ll) > 0x0000FFFF || data.size >= 4) { buf[i - start_offset + ++data.bytes_grown] = data.a[2]; buf[i - start_offset + ++data.bytes_grown] = data.a[3]; } From 9fe6820236169bd154bb54cff867351900795fcf Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:36:57 +0100 Subject: [PATCH 11/38] Add double type for terminal write in anticipation of future avr-libc extension --- src/term.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/term.c b/src/term.c index 7481f0ee..6efa380a 100644 --- a/src/term.c +++ b/src/term.c @@ -417,6 +417,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Data union union { float f; + double d; int64_t ll; uint64_t ull; uint8_t a[8]; @@ -524,12 +525,19 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } - if(!data.size) { // Data item was not recognised as integer - // Try float + if(!data.size) { // Try float data.f = strtof(argi, &end_ptr); - if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) { + if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) data.size = 4; - } else { + } + + if(!data.size) { // Try double + data.d = strtod(argi, &end_ptr); + if (end_ptr != argi && *end_ptr == 0) + data.size = 8; + } + + if(!data.size) { // Try single character if (argi[0] == '\'' && argi[2] == '\'') { data.ll = argi[1]; @@ -553,7 +561,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, return -1; } } - } } } if(data.str_ptr) { From 5c4cfa642aa32d268224c503555e3a1b196b38df Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:39:02 +0100 Subject: [PATCH 12/38] Parse terminal writes of string and character constants in C-style --- src/term.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 200 insertions(+), 21 deletions(-) diff --git a/src/term.c b/src/term.c index 6efa380a..cd7e3b45 100644 --- a/src/term.c +++ b/src/term.c @@ -335,6 +335,179 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } + +// convert the next n hex digits of s to a hex number +static unsigned int tohex(const char *s, unsigned int n) { + int ret, c; + + ret = 0; + while(n--) { + ret *= 16; + c = *s++; + ret += c >= '0' && c <= '9'? c - '0': c >= 'a' && c <= 'f'? c - 'a' + 10: c - 'A' + 10; + } + + return ret; +} + +/* + * Create a utf-8 character sequence from a single unicode character. + * Permissive for some invalid unicode sequences but not for those with + * high bit set). Returns numbers of characters written (0-6). + */ +static int wc_to_utf8str(unsigned int wc, char *str) { + if(!(wc & ~0x7fu)) { + *str = (char) wc; + return 1; + } + if(!(wc & ~0x7ffu)) { + *str++ = (char) ((wc >> 6) | 0xc0); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 2; + } + if(!(wc & ~0xffffu)) { + *str++ = (char) ((wc >> 12) | 0xe0); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 3; + } + if(!(wc & ~0x1fffffu)) { + *str++ = (char) ((wc >> 18) | 0xf0); + *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 4; + } + if(!(wc & ~0x3ffffffu)) { + *str++ = (char) ((wc >> 24) | 0xf8); + *str++ = (char) (((wc >> 18) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 5; + } + if(!(wc & ~0x7fffffffu)) { + *str++ = (char) ((wc >> 30) | 0xfc); + *str++ = (char) (((wc >> 24) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 18) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 12) & 0x3f) | 0x80); + *str++ = (char) (((wc >> 6) & 0x3f) | 0x80); + *str++ = (char) ((wc & 0x3f) | 0x80); + return 6; + } + return 0; +} + +// Unescape C-style strings, destination d must hold enough space (and can be source s) +static char *unescape(char *d, const char *s) { + char *ret = d; + int n, k; + + while(*s) { + switch (*s) { + case '\\': + switch (*++s) { + case 'n': + *d = '\n'; + break; + case 't': + *d = '\t'; + break; + case 'a': + *d = '\a'; + break; + case 'b': + *d = '\b'; + break; + case 'e': // non-standard ESC + *d = 27; + break; + case 'f': + *d = '\f'; + break; + case 'r': + *d = '\r'; + break; + case 'v': + *d = '\v'; + break; + case '?': + *d = '?'; + break; + case '`': + *d = '`'; + break; + case '"': + *d = '"'; + break; + case '\'': + *d = '\''; + break; + case '\\': + *d = '\\'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': // 1-3 octal digits + n = *s - '0'; + for(k = 0; k < 2 && s[1] >= '0' && s[1] <= '7'; k++) // max 2 more octal characters + n *= 8, n += s[1] - '0', s++; + *d = n; + break; + case 'x': // unlimited hex digits + for(k = 0; isxdigit(s[k + 1]); k++) + continue; + if(k > 0) { + *d = tohex(s + 1, k); + s += k; + } else { // no hex digits after \x? copy \x + *d++ = '\\'; + *d = 'x'; + } + break; + case 'u': // exactly 4 hex digits and valid unicode + if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && + (n = wc_to_utf8str(tohex(s+1, 4), d))) { + d += n - 1; + s += 4; + } else { // invalid \u sequence? copy \u + *d++ = '\\'; + *d = 'u'; + } + break; + case 'U': // exactly 6 hex digits and valid unicode + if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]) && isxdigit(s[6]) && + (n = wc_to_utf8str(tohex(s+1, 6), d))) { + d += n - 1; + s += 6; + } else { // invalid \U sequence? copy \U + *d++ = '\\'; + *d = 'U'; + } + break; + default: // keep the escape sequence (C would warn and remove \) + *d++ = '\\'; + *d = *s; + } + break; + + default: // not an escape sequence: just copy the character + *d = *s; + } + d++; + s++; + } + *d = *s; // terminate + + return ret; +} + + static size_t maxstrlen(int argc, char **argv) { size_t max = 0; @@ -537,32 +710,38 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.size = 8; } - if(!data.size) { - // Try single character - if (argi[0] == '\'' && argi[2] == '\'') { - data.ll = argi[1]; - data.size = 1; - } else { - // Try string that starts and ends with quotes - if (argi[0] == '\"' && argi[arglen - 1] == '\"') { - data.str_ptr = calloc(arglen, sizeof(char)); - if (data.str_ptr == NULL) { - avrdude_message(MSG_INFO, "%s (write str): out of memory\n", progname); - return -1; - } - // Strip start and end quotes - strncpy(data.str_ptr, argi + 1, arglen - 2); - } else { - avrdude_message(MSG_INFO, "\n%s (write): can't parse data '%s'\n", - progname, argi); + if(!data.size) { // Try C-style string or single character + if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { + char *s = calloc(arglen-1, 1); + if (s == NULL) { + avrdude_message(MSG_INFO, "%s (write str): out of memory\n", progname); free(buf); - if(data.str_ptr != NULL) - free(data.str_ptr); return -1; - } } + // Strip start and end quotes, and unescape C string + strncpy(s, argi+1, arglen-2); + unescape(s, s); + if (*argi == '\'') { // single C-style character + if(*s && s[1]) + avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", + progname, argi); + data.ll = *s; + data.size = 1; + free(s); + } else { // C-style string + data.str_ptr = s; + } + } else { + avrdude_message(MSG_INFO, "\n%s (write): can't parse data '%s'\n", + progname, argi); + free(buf); + if(data.str_ptr != NULL) + free(data.str_ptr); + return -1; + } } } + if(data.str_ptr) { for(int16_t j = 0; j < strlen(data.str_ptr); j++) buf[i - start_offset + data.bytes_grown++] = (uint8_t)data.str_ptr[j]; From 0b2f38c67d3501f997a7840ff2f0791cfc3e06cd Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:39:52 +0100 Subject: [PATCH 13/38] Allow optional comma separators for data items in terminal write --- src/term.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/term.c b/src/term.c index cd7e3b45..f4472452 100644 --- a/src/term.c +++ b/src/term.c @@ -616,6 +616,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.str_ptr = NULL; } + // remove trailing comma to allow cut and paste of lists + if(arglen > 0 && argi[arglen-1] == ',') + argi[--arglen] = 0; + // Try integers and assign data size errno = 0; data.ull = strtoull(argi, &end_ptr, 0); From ddffabe86adb3aa3aabc24ea2f7829725602e5b9 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:40:40 +0100 Subject: [PATCH 14/38] Improve terminal write usage message --- src/term.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/term.c b/src/term.c index f4472452..1b563f46 100644 --- a/src/term.c +++ b/src/term.c @@ -523,10 +523,33 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, { if (argc < 4) { avrdude_message(MSG_INFO, - "Usage: write \n" - " write <...>\n\n" - " Add a suffix to manually specify the size for each field:\n" - " HH/hh: 8-bit, H/h/S/s: 16-bit, L/l: 32-bit, LL/ll: 64-bit, F/f: 32-bit float\n"); + "Usage: write [,] {[,]} \n" + " write [,] {[,]} ...\n" + "\n" + "Ellipsis ... writes bytes padded by repeating the last item.\n" + "\n" + " can be hexadecimal, octal or decimal integers, double, float or\n" + "C-style strings and chars. For numbers, an optional case-insensitive suffix\n" + "specifies the data size: HH: 8 bit, H/S: 16 bit, L: 32 bit, LL: 64 bit, F:\n" + "32-bit float. Hexadecimal floating point notation is supported. The\n" + "ambiguous trailing F in 0x1.8F makes the number be interpreted as double;\n" + "use a zero exponent as in 0x1.8p0F to denote a hexadecimal float.\n" + "\n" + "An optional U suffix makes a number unsigned. Ordinary 0x hex numbers are\n" + "always treated as unsigned. +0x or -0x hex numbers are treated as signed\n" + "unless they have a U suffix. Unsigned integers cannot be larger than 2^64-1.\n" + "If n is an unsigned integer then -n is also a valid unsigned integer as in C.\n" + "Signed integers must fall into the [-2^63, 2^63-1] range or a correspondingly\n" + "smaller range when a suffix specifies a smaller type. Out of range signed\n" + "numbers trigger a warning.\n" + "\n" + "Ordinary 0x hex numbers with n hex digits (counting leading zeros) use\n" + "the smallest size of 1, 2, 4 and 8 bytes that can accommodate any n-digit hex\n" + "number. If a suffix specifies a size explicitly the corresponding number of\n" + "least significant bytes are written. Otherwise, signed and unsigned integers\n" + "alike occupy the smallest of 1, 2, 4, or 8 bytes needed to accommodate them\n" + "in their respective representation.\n" + ); return -1; } From aa09bcf9007481791f19ed3ac9e531aa1a04c54c Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:42:59 +0100 Subject: [PATCH 15/38] Ensure terminal writes little endian numbers --- src/term.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 1b563f46..65e5c850 100644 --- a/src/term.c +++ b/src/term.c @@ -518,6 +518,16 @@ static size_t maxstrlen(int argc, char **argv) { return max; } + +// Change data item p of size bytes from big endian to little endian and vice versa +static void change_endian(void *p, int size) { + uint8_t tmp, *w = p; + + for(int i=0; i 1) + change_endian(data.a, data.size); } if(data.str_ptr) { From 7205bbae80eb033978bd1c3ffc26d81c0b424522 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:43:45 +0100 Subject: [PATCH 16/38] Enhance terminal read with new mode: read --- src/term.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 65e5c850..441868e0 100644 --- a/src/term.c +++ b/src/term.c @@ -255,7 +255,8 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, // Get start address if present char * end_ptr; static uint32_t addr = 0; - if (argc == 4) { + + if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { avrdude_message(MSG_INFO, "%s (%s): can't parse address \"%s\"\n", From 602e9bb80c85c162a2c448b42c341e4249369640 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:44:20 +0100 Subject: [PATCH 17/38] Change size for memory type variable in terminal read --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 441868e0..fe3cebfc 100644 --- a/src/term.c +++ b/src/term.c @@ -242,7 +242,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } enum { read_size = 256 }; - static char prevmem[128] = {0x00}; + static char prevmem[AVR_MEMDESCLEN] = {0x00}; char * memtype = argv[1]; AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { From 92425af0cc004ee5466ec0c576d8152d10a3b5c5 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:47:33 +0100 Subject: [PATCH 18/38] Improve terminal dump usage message --- src/term.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/term.c b/src/term.c index fe3cebfc..01fb2560 100644 --- a/src/term.c +++ b/src/term.c @@ -232,13 +232,15 @@ static int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len) static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { - if (argc < 2) { - avrdude_message(MSG_INFO, "Usage: %s [ ]\n" - " %s [ <...>]\n" - " %s <...>\n" - " %s \n", - argv[0], argv[0], argv[0], argv[0]); - return -1; + if (argc < 2 || argc > 4) { + avrdude_message(MSG_INFO, + "Usage: %s \n" + " %s ...\n" + " %s \n" + " %s ...\n" + " %s \n", + argv[0], argv[0], argv[0], argv[0], argv[0]); + return -1; } enum { read_size = 256 }; From c5f522342d394bb8a6b22879dc79be413ea93558 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:50:23 +0100 Subject: [PATCH 19/38] Improve terminal help message --- src/term.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/term.c b/src/term.c index 01fb2560..3e9fdd59 100644 --- a/src/term.c +++ b/src/term.c @@ -92,13 +92,13 @@ static int cmd_verbose (PROGRAMMER * pgm, struct avrpart * p, int argc, char *argv[]); struct command cmd[] = { - { "dump", cmd_dump, "dump memory : %s " }, + { "dump", cmd_dump, "%s [ | ... | | ...]" }, { "read", cmd_dump, "alias for dump" }, - { "write", cmd_write, "write memory : %s ... " }, + { "write", cmd_write, "%s [[,] {[,]} | [,] {[,]} ...]" }, { "erase", cmd_erase, "perform a chip erase" }, { "sig", cmd_sig, "display device signature bytes" }, { "part", cmd_part, "display the current part information" }, - { "send", cmd_send, "send a raw command : %s " }, + { "send", cmd_send, "send a raw command: %s " }, { "parms", cmd_parms, "display adjustable parameters (STK500 and Curiosity Nano only)" }, { "vtarg", cmd_vtarg, "set (STK500 and Curiosity Nano only)" }, { "varef", cmd_varef, "set (STK500 only)" }, @@ -1162,9 +1162,9 @@ static int cmd_help(PROGRAMMER * pgm, struct avrpart * p, { int i; - fprintf(stdout, "Valid commands:\n\n"); + fprintf(stdout, "Valid commands:\n"); for (i=0; i Date: Tue, 12 Jul 2022 11:51:04 +0100 Subject: [PATCH 20/38] Remove echo of tokenised terminal command --- src/term.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/term.c b/src/term.c index 3e9fdd59..e7185593 100644 --- a/src/term.c +++ b/src/term.c @@ -1388,7 +1388,6 @@ char * terminal_get_input(const char *prompt) int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) { char * cmdbuf; - int i; char * q; int rc; int argc; @@ -1414,10 +1413,12 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return argc; } +#if 0 fprintf(stdout, ">>> "); - for (i=0; i Date: Tue, 12 Jul 2022 11:58:51 +0100 Subject: [PATCH 21/38] Consolidate error messages in term.c --- src/term.c | 149 ++++++++++++++++++++++++++--------------------------- 1 file changed, 74 insertions(+), 75 deletions(-) diff --git a/src/term.c b/src/term.c index e7185593..6d146c66 100644 --- a/src/term.c +++ b/src/term.c @@ -248,8 +248,8 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n", - memtype, p->desc); + avrdude_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", + progname, memtype, p->desc); return -1; } uint32_t maxsize = mem->size; @@ -261,12 +261,12 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - avrdude_message(MSG_INFO, "%s (%s): can't parse address \"%s\"\n", - progname, argv[0], argv[2]); + avrdude_message(MSG_INFO, "%s (dump): can't parse address %s\n", + progname, argv[2]); return -1; } else if (addr >= maxsize) { - avrdude_message(MSG_INFO, "%s (%s): address 0x%05lx is out of range for %s memory\n", - progname, argv[0], addr, mem->desc); + avrdude_message(MSG_INFO, "%s (dump): address 0x%05lx is out of range for %s memory\n", + progname, (long) addr, mem->desc); return -1; } } @@ -282,8 +282,8 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } else if (argc == 4) { len = strtol(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (%s): can't parse length \"%s\"\n", - progname, argv[0], argv[3]); + avrdude_message(MSG_INFO, "%s (dump): can't parse length %s\n", + progname, argv[3]); return -1; } } else { @@ -317,10 +317,10 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, int32_t rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n", - mem->desc, addr + i, p->desc); + mem->desc, (long) addr + i, p->desc); if (rc == -1) - avrdude_message(MSG_INFO, "read operation not supported on memory type \"%s\"\n", - mem->desc); + avrdude_message(MSG_INFO, "read operation not supported on memory type %s\n", + mem->desc); return -1; } report_progress(i, len, NULL); @@ -573,8 +573,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; // Memory name string AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n", - memtype, p->desc); + avrdude_message(MSG_INFO, "%s memory type not defined for part %s\n", + memtype, p->desc); return -1; } uint32_t maxsize = mem->size; @@ -582,14 +582,14 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * end_ptr; int32_t addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - avrdude_message(MSG_INFO, "%s (write): can't parse address \"%s\"\n", - progname, argv[2]); + avrdude_message(MSG_INFO, "%s (write): can't parse address %s\n", + progname, argv[2]); return -1; } if (addr > maxsize) { avrdude_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n", - progname, addr, memtype); + progname, (long) addr, memtype); return -1; } @@ -606,8 +606,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, start_offset = 4; len = strtoul(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (write ...): can't parse length \"%s\"\n", - progname, argv[3]); + avrdude_message(MSG_INFO, "%s (write ...): can't parse length %s\n", + progname, argv[3]); free(buf); return -1; } @@ -639,7 +639,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, }; if(sizeof(long long) != sizeof(int64_t) || (data.a[0]^data.a[7]) != 1) - avrdude_message(MSG_INFO, "%s (write): assumption on data types not met? check source and recompile\n", progname); + avrdude_message(MSG_INFO, "%s (write): assumption on data types not met? " + "Check source and recompile\n", progname); bool is_big_endian = data.a[7]; for (i = start_offset; i < len + start_offset; i++) { @@ -734,10 +735,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, 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)": "" - ); + "interpreted as %d-byte %lld; consider 'U' suffix\n", + progname, argi, data.size*8, data.size, data.ll); } } } @@ -768,7 +767,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if (*argi == '\'') { // single C-style character if(*s && s[1]) avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", - progname, argi); + progname, argi); data.ll = *s; data.size = 1; free(s); @@ -776,8 +775,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.str_ptr = s; } } else { - avrdude_message(MSG_INFO, "\n%s (write): can't parse data '%s'\n", - progname, argi); + avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", + progname, argi); free(buf); if(data.str_ptr != NULL) free(data.str_ptr); @@ -819,8 +818,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if ((addr + len + data.bytes_grown) > maxsize) { avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed " - "range for %s memory\n", - progname, memtype); + "range for %s memory\n", progname, memtype); free(buf); return -1; } @@ -828,8 +826,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(data.str_ptr) free(data.str_ptr); - avrdude_message(MSG_NOTICE, "\nInfo: Writing %d bytes starting from address 0x%02x", - len + data.bytes_grown, addr); + avrdude_message(MSG_NOTICE, "\nInfo: Writing %d bytes starting from address 0x%02lx", + len + data.bytes_grown, (long) addr); if (write_mode == WRITE_MODE_FILL) avrdude_message(MSG_NOTICE, ". Remaining space filled with %s", argv[argc - 2]); avrdude_message(MSG_NOTICE, "\n"); @@ -841,10 +839,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int32_t rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]); if (rc) { avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", - progname, buf[i], addr+i, rc); + progname, buf[i], (long) addr+i, (int) rc); if (rc == -1) - avrdude_message(MSG_INFO, "write operation not supported on memory type \"%s\"\n", - mem->desc); + avrdude_message(MSG_INFO, "write operation not supported on memory type %s\n", + mem->desc); werror = true; } @@ -852,7 +850,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, rc = pgm->read_byte(pgm, p, mem, addr+i, &b); if (b != buf[i]) { avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n", - progname, buf[i], addr+i, b); + progname, buf[i], (long) addr+i, b); werror = true; } @@ -879,14 +877,14 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p, int len; if (pgm->cmd == NULL) { - avrdude_message(MSG_INFO, "The %s programmer does not support direct ISP commands.\n", - pgm->type); + avrdude_message(MSG_INFO, "%s (send): the %s programmer does not support direct ISP commands\n", + progname, pgm->type); return -1; } if (spi_mode && (pgm->spi == NULL)) { - avrdude_message(MSG_INFO, "The %s programmer does not support direct SPI transfers.\n", - pgm->type); + avrdude_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", + progname, pgm->type); return -1; } @@ -905,8 +903,8 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p, for (i=1; idesc); + avrdude_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n", + progname, p->desc); } else { fprintf(stdout, "Device signature = 0x"); @@ -997,8 +995,7 @@ static int cmd_parms(PROGRAMMER * pgm, struct avrpart * p, { if (pgm->print_parms == NULL) { avrdude_message(MSG_INFO, "%s (parms): the %s programmer does not support " - "adjustable parameters\n", - progname, pgm->type); + "adjustable parameters\n", progname, pgm->type); return -1; } pgm->print_parms(pgm); @@ -1020,18 +1017,18 @@ static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p, } v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (vtarg): can't parse voltage \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n", + progname, argv[1]); return -1; } if (pgm->set_vtarget == NULL) { avrdude_message(MSG_INFO, "%s (vtarg): the %s programmer cannot set V[target]\n", - progname, pgm->type); + progname, pgm->type); return -2; } if ((rc = pgm->set_vtarget(pgm, v)) != 0) { avrdude_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n", - progname, rc); + progname, rc); return -3; } return 0; @@ -1054,8 +1051,8 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, if (strcmp(argv[1], "off") == 0) v = 0.0; else { - avrdude_message(MSG_INFO, "%s (fosc): can't parse frequency \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n", + progname, argv[1]); return -1; } } @@ -1065,12 +1062,12 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, v *= 1e3; if (pgm->set_fosc == NULL) { avrdude_message(MSG_INFO, "%s (fosc): the %s programmer cannot set oscillator frequency\n", - progname, pgm->type); + progname, pgm->type); return -2; } if ((rc = pgm->set_fosc(pgm, v)) != 0) { avrdude_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n", - progname, rc); + progname, rc); return -3; } return 0; @@ -1090,19 +1087,19 @@ static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p, } v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (sck): can't parse period \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (sck): can't parse period %s\n", + progname, argv[1]); return -1; } v *= 1e-6; /* Convert from microseconds to seconds. */ if (pgm->set_sck_period == NULL) { avrdude_message(MSG_INFO, "%s (sck): the %s programmer cannot set SCK period\n", - progname, pgm->type); + progname, pgm->type); return -2; } if ((rc = pgm->set_sck_period(pgm, v)) != 0) { avrdude_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n", - progname, rc); + progname, rc); return -3; } return 0; @@ -1125,32 +1122,32 @@ static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p, chan = 0; v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse voltage \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", + progname, argv[1]); return -1; } } else { chan = strtoul(argv[1], &endp, 10); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse channel \"%s\"\n", - progname, argv[1]); + avrdude_message(MSG_INFO, "%s (varef): can't parse channel %s\n", + progname, argv[1]); return -1; } v = strtod(argv[2], &endp); if (endp == argv[2]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse voltage \"%s\"\n", - progname, argv[2]); + avrdude_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", + progname, argv[2]); return -1; } } if (pgm->set_varef == NULL) { avrdude_message(MSG_INFO, "%s (varef): the %s programmer cannot set V[aref]\n", - progname, pgm->type); + progname, pgm->type); return -2; } if ((rc = pgm->set_varef(pgm, chan, v)) != 0) { avrdude_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n", - progname, rc); + progname, rc); return -3; } return 0; @@ -1183,7 +1180,8 @@ static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p, spi_mode = 1; return 0; } - avrdude_message(MSG_INFO, "`spi' command unavailable for this programmer type\n"); + avrdude_message(MSG_INFO, "%s: spi command unavailable for this programmer type\n", + progname); return -1; } @@ -1196,7 +1194,8 @@ static int cmd_pgm(PROGRAMMER * pgm, struct avrpart * p, pgm->initialize(pgm, p); return 0; } - avrdude_message(MSG_INFO, "`pgm' command unavailable for this programmer type\n"); + avrdude_message(MSG_INFO, "%s: pgm command unavailable for this programmer type\n", + progname); return -1; } @@ -1216,13 +1215,13 @@ static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p, } nverb = strtol(argv[1], &endp, 0); if (endp == argv[2]) { - avrdude_message(MSG_INFO, "%s: can't parse verbosity level \"%s\"\n", - progname, argv[2]); + avrdude_message(MSG_INFO, "%s: can't parse verbosity level %s\n", + progname, argv[2]); return -1; } if (nverb < 0) { avrdude_message(MSG_INFO, "%s: verbosity level must be positive: %d\n", - progname, nverb); + progname, nverb); return -1; } verbose = nverb; @@ -1344,8 +1343,8 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p, } else if (strncasecmp(argv[0], cmd[i].name, len)==0) { if (hold != -1) { - avrdude_message(MSG_INFO, "%s: command \"%s\" is ambiguous\n", - progname, argv[0]); + avrdude_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", + progname, argv[0]); return -1; } hold = i; @@ -1355,8 +1354,8 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p, if (hold != -1) return cmd[hold].func(pgm, p, argc, argv); - avrdude_message(MSG_INFO, "%s: invalid command \"%s\"\n", - progname, argv[0]); + avrdude_message(MSG_INFO, "%s (cmd): invalid command %s\n", + progname, argv[0]); return -1; } From 704d2536368a421da11a1d57c55907bbc027b3c2 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 11:59:42 +0100 Subject: [PATCH 22/38] Remove comparisons between signed and unsigned integers in term.c --- src/term.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/term.c b/src/term.c index 6d146c66..865a413c 100644 --- a/src/term.c +++ b/src/term.c @@ -112,7 +112,7 @@ struct command cmd[] = { { "quit", cmd_quit, "quit" } }; -#define NCMDS (sizeof(cmd)/sizeof(struct command)) +#define NCMDS ((int)(sizeof(cmd)/sizeof(struct command))) @@ -157,8 +157,8 @@ static int hexdump_line(char * buffer, unsigned char * p, int n, int pad) { char * hexdata = "0123456789abcdef"; char * b = buffer; - int32_t i = 0; - int32_t j = 0; + int i = 0; + int j = 0; for (i=0; i len) n = len; hexdump_line(dst1, p, n, 48); @@ -252,11 +252,11 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, progname, memtype, p->desc); return -1; } - uint32_t maxsize = mem->size; + int maxsize = mem->size; // Get start address if present char * end_ptr; - static uint32_t addr = 0; + static int addr = 0; if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); @@ -272,7 +272,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } // Get no. bytes to read if present - static int32_t len = read_size; + static int len = read_size; if (argc >= 3) { memset(prevmem, 0x00, sizeof(prevmem)); if (strcmp(argv[argc - 1], "...") == 0) { @@ -313,8 +313,8 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } report_progress(0, 1, "Reading"); - for (uint32_t i = 0; i < len; i++) { - int32_t rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); + for (int i = 0; i < len; i++) { + int rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n", mem->desc, (long) addr + i, p->desc); @@ -566,10 +566,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, return -1; } - int32_t i; + int i; uint8_t write_mode; // Operation mode, "standard" or "fill" uint8_t start_offset; // Which argc argument - int32_t len; // Number of bytes to write to memory + int len; // Number of bytes to write to memory char * memtype = argv[1]; // Memory name string AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { @@ -577,10 +577,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, memtype, p->desc); return -1; } - uint32_t maxsize = mem->size; + int maxsize = mem->size; char * end_ptr; - int32_t addr = strtoul(argv[2], &end_ptr, 0); + int addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { avrdude_message(MSG_INFO, "%s (write): can't parse address %s\n", progname, argv[2]); @@ -620,7 +620,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Structure related to data that is being written to memory struct Data { // Data info - int32_t bytes_grown; + int bytes_grown; uint8_t size; char * str_ptr; // Data union @@ -789,7 +789,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } if(data.str_ptr) { - for(int16_t j = 0; j < strlen(data.str_ptr); j++) + for(size_t j = 0; j < strlen(data.str_ptr); j++) buf[i - start_offset + data.bytes_grown++] = (uint8_t)data.str_ptr[j]; } else { buf[i - start_offset + data.bytes_grown] = data.a[0]; @@ -836,7 +836,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, bool werror = false; report_progress(0, 1, "Writing"); for (i = 0; i < (len + data.bytes_grown); i++) { - int32_t rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]); + int rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]); if (rc) { avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", progname, buf[i], (long) addr+i, (int) rc); @@ -960,7 +960,7 @@ static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p, rc = avr_signature(pgm, p); if (rc != 0) { avrdude_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n", - prgname, rc); + progname, rc); } m = avr_locate_mem(p, "signature"); From 7c766ef9bd9dd35c011ad583351909d744222985 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 12:01:14 +0100 Subject: [PATCH 23/38] Refine type detection in terminal write The code no longer accepts valid mantissa-only doubles that are integer rejects, eg, 078 or ULL overflows. These are most likely input errors by the user: 8 is not an octal digit, they might have typed 17 hex digits, not 16. It's just too hard to explain that 0xffffFFFFffffFFFFf writes 0x4430000000000000, which is the correct double representation of the valid 17-digit hex mantissa that strtod() is perfectly happy to accept. --- src/term.c | 55 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/term.c b/src/term.c index 865a413c..1f5ec4b4 100644 --- a/src/term.c +++ b/src/term.c @@ -531,6 +531,30 @@ static void change_endian(void *p, int size) { } +// Looks like a double mantissa in hex or dec notation +static int is_mantissa_only(char *p) { + char *digs; + + if(*p == '+' || *p == '-') + p++; + + if(*p == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + digs = "0123456789abcdefABCDEF"; + } else + digs = "0123456789"; + + if(!*p) + return 0; + + while(*p) + if(!strchr(digs, *p++)) + return 0; + + return 1; +} + + static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { @@ -741,18 +765,20 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } + if(!data.size) { // Try double now that input was rejected as integer + data.d = strtod(argi, &end_ptr); + // Do not accept valid doubles that are integer rejects (eg, 078 or ULL overflows) + if (end_ptr != argi && *end_ptr == 0) + if (!is_mantissa_only(argi)) + data.size = 8; + } + if(!data.size) { // Try float data.f = strtof(argi, &end_ptr); if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) data.size = 4; } - if(!data.size) { // Try double - data.d = strtod(argi, &end_ptr); - if (end_ptr != argi && *end_ptr == 0) - data.size = 8; - } - if(!data.size) { // Try C-style string or single character if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { char *s = calloc(arglen-1, 1); @@ -774,16 +800,17 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } else { // C-style string data.str_ptr = s; } - } else { - avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", - progname, argi); - free(buf); - if(data.str_ptr != NULL) - free(data.str_ptr); - return -1; } } - // ensure we have little endian representation in data.a + + if(!data.size && !data.str_ptr) { + avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", + progname, argi); + free(buf); + return -1; + } + + // Assume endianness is the same for double and int, and ensure little endian representation if(is_big_endian && data.size > 1) change_endian(data.a, data.size); } From f871a4dc1ea57c417b9c8fe4c2731fa330853f73 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 12:02:33 +0100 Subject: [PATCH 24/38] Adapt capitalisation of comments in term.c to existing style --- src/term.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/term.c b/src/term.c index 1f5ec4b4..181a3b4a 100644 --- a/src/term.c +++ b/src/term.c @@ -339,7 +339,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, -// convert the next n hex digits of s to a hex number +// Convert the next n hex digits of s to a hex number static unsigned int tohex(const char *s, unsigned int n) { int ret, c; @@ -422,7 +422,7 @@ static char *unescape(char *d, const char *s) { case 'b': *d = '\b'; break; - case 'e': // non-standard ESC + case 'e': // Non-standard ESC *d = 27; break; case 'f': @@ -458,54 +458,54 @@ static char *unescape(char *d, const char *s) { case '6': case '7': // 1-3 octal digits n = *s - '0'; - for(k = 0; k < 2 && s[1] >= '0' && s[1] <= '7'; k++) // max 2 more octal characters + for(k = 0; k < 2 && s[1] >= '0' && s[1] <= '7'; k++) // Max 2 more octal characters n *= 8, n += s[1] - '0', s++; *d = n; break; - case 'x': // unlimited hex digits + case 'x': // Unlimited hex digits for(k = 0; isxdigit(s[k + 1]); k++) continue; if(k > 0) { *d = tohex(s + 1, k); s += k; - } else { // no hex digits after \x? copy \x + } else { // No hex digits after \x? copy \x *d++ = '\\'; *d = 'x'; } break; - case 'u': // exactly 4 hex digits and valid unicode + case 'u': // Exactly 4 hex digits and valid unicode if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && (n = wc_to_utf8str(tohex(s+1, 4), d))) { d += n - 1; s += 4; - } else { // invalid \u sequence? copy \u + } else { // Invalid \u sequence? copy \u *d++ = '\\'; *d = 'u'; } break; - case 'U': // exactly 6 hex digits and valid unicode + case 'U': // Exactly 6 hex digits and valid unicode if(isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]) && isxdigit(s[6]) && (n = wc_to_utf8str(tohex(s+1, 6), d))) { d += n - 1; s += 6; - } else { // invalid \U sequence? copy \U + } else { // Invalid \U sequence? copy \U *d++ = '\\'; *d = 'U'; } break; - default: // keep the escape sequence (C would warn and remove \) + default: // Keep the escape sequence (C would warn and remove \) *d++ = '\\'; *d = *s; } break; - default: // not an escape sequence: just copy the character + default: // Not an escape sequence: just copy the character *d = *s; } d++; s++; } - *d = *s; // terminate + *d = *s; // Terminate return ret; } @@ -681,7 +681,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.str_ptr = NULL; } - // remove trailing comma to allow cut and paste of lists + // Remove trailing comma to allow cut and paste of lists if(arglen > 0 && argi[arglen-1] == ',') argi[--arglen] = 0; @@ -692,7 +692,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, unsigned int nu=0, nl=0, nh=0, ns=0, nx=0; char *p; - // parse suffixes: ULL, LL, UL, L ... UHH, HH + // Parse suffixes: ULL, LL, UL, L ... UHH, HH for(p=end_ptr; *p; p++) switch(toupper(*p)) { case 'U': nu++; break; @@ -702,10 +702,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, default: nx++; } - 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 + 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; @@ -715,13 +715,13 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, 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(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 + // Smallest size that fits signed representation data.size = is_outside_int64_t? 8: data.ll < INT32_MIN || data.ll > INT32_MAX? 8: @@ -729,7 +729,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.ll < INT8_MIN || data.ll > INT8_MAX? 2: 1; } else { - // smallest size that fits unsigned representation + // Smallest size that fits unsigned representation data.size = data.ull > UINT32_MAX? 8: data.ull > UINT16_MAX? 4: @@ -767,7 +767,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(!data.size) { // Try double now that input was rejected as integer data.d = strtod(argi, &end_ptr); - // Do not accept valid doubles that are integer rejects (eg, 078 or ULL overflows) + // Do not accept valid mantissa-only doubles that are integer rejects (eg, 078 or ULL overflows) if (end_ptr != argi && *end_ptr == 0) if (!is_mantissa_only(argi)) data.size = 8; @@ -790,7 +790,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Strip start and end quotes, and unescape C string strncpy(s, argi+1, arglen-2); unescape(s, s); - if (*argi == '\'') { // single C-style character + if (*argi == '\'') { // Single C-style character if(*s && s[1]) avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", progname, argi); From 63fb79accbf867af563f83163410b58f0e7f832d Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 12:24:30 +0100 Subject: [PATCH 25/38] Consolidate more error messages in term.c --- src/term.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/term.c b/src/term.c index 181a3b4a..8dc44233 100644 --- a/src/term.c +++ b/src/term.c @@ -316,11 +316,11 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, for (int i = 0; i < len; i++) { int rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { - avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n", - mem->desc, (long) addr + i, p->desc); + avrdude_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n", + progname, mem->desc, (long) addr + i, p->desc); if (rc == -1) - avrdude_message(MSG_INFO, "read operation not supported on memory type %s\n", - mem->desc); + avrdude_message(MSG_INFO, "%*sread operation not supported on memory type %s\n", + (int) strlen(progname)+9, "", mem->desc); return -1; } report_progress(i, len, NULL); @@ -597,8 +597,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; // Memory name string AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "%s memory type not defined for part %s\n", - memtype, p->desc); + avrdude_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", + progname, memtype, p->desc); return -1; } int maxsize = mem->size; @@ -853,10 +853,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(data.str_ptr) free(data.str_ptr); - avrdude_message(MSG_NOTICE, "\nInfo: Writing %d bytes starting from address 0x%02lx", + avrdude_message(MSG_NOTICE, "Info: writing %d bytes starting from address 0x%02lx", len + data.bytes_grown, (long) addr); if (write_mode == WRITE_MODE_FILL) - avrdude_message(MSG_NOTICE, ". Remaining space filled with %s", argv[argc - 2]); + avrdude_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]); avrdude_message(MSG_NOTICE, "\n"); pgm->err_led(pgm, OFF); @@ -868,8 +868,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", progname, buf[i], (long) addr+i, (int) rc); if (rc == -1) - avrdude_message(MSG_INFO, "write operation not supported on memory type %s\n", - mem->desc); + avrdude_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n", + (int) strlen(progname)+10, "", mem->desc); werror = true; } From d9cb9772d7bfd1569d85fb6eef98cf7bc8c7111f Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 12:30:29 +0100 Subject: [PATCH 26/38] Fix verbosity level parsing in term.c --- src/term.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/term.c b/src/term.c index 8dc44233..41b172ec 100644 --- a/src/term.c +++ b/src/term.c @@ -1241,13 +1241,13 @@ static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p, return 0; } nverb = strtol(argv[1], &endp, 0); - if (endp == argv[2]) { - avrdude_message(MSG_INFO, "%s: can't parse verbosity level %s\n", - progname, argv[2]); + if (endp == argv[1] || *endp) { + avrdude_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n", + progname, argv[1]); return -1; } if (nverb < 0) { - avrdude_message(MSG_INFO, "%s: verbosity level must be positive: %d\n", + avrdude_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n", progname, nverb); return -1; } From 1e8b56751e4368db5abbf09337610916965df0cc Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 13:11:10 +0100 Subject: [PATCH 27/38] Add quell command in terminal Sets the quell_progress global variable that can be, and is, consulted by programmers. Setting quell_progress to a positive number also switches off progress bars. It is currently not possible to switch on progress bars again: that is enabled in main.c once at the start of AVRDUDE. That code in main should move to avr.c to enable report_update() to consult quell_progress directly. Will do at another time when touching main.c and avr.c. smr --- src/term.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/term.c b/src/term.c index 41b172ec..5050938b 100644 --- a/src/term.c +++ b/src/term.c @@ -91,6 +91,9 @@ static int cmd_pgm (PROGRAMMER * pgm, struct avrpart * p, static int cmd_verbose (PROGRAMMER * pgm, struct avrpart * p, int argc, char *argv[]); +static int cmd_quell (PROGRAMMER * pgm, struct avrpart * p, + int argc, char *argv[]); + struct command cmd[] = { { "dump", cmd_dump, "%s [ | ... | | ...]" }, { "read", cmd_dump, "alias for dump" }, @@ -107,6 +110,7 @@ struct command cmd[] = { { "spi", cmd_spi, "enter direct SPI mode" }, { "pgm", cmd_pgm, "return to programming mode" }, { "verbose", cmd_verbose, "change verbosity" }, + { "quell", cmd_quell, "set quell level for progress bars" }, { "help", cmd_help, "help" }, { "?", cmd_help, "help" }, { "quit", cmd_quit, "quit" } @@ -1257,6 +1261,40 @@ static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p, return 0; } +static int cmd_quell(PROGRAMMER * pgm, struct avrpart * p, + int argc, char * argv[]) +{ + int nquell; + char *endp; + + if (argc != 1 && argc != 2) { + avrdude_message(MSG_INFO, "Usage: quell []\n"); + return -1; + } + if (argc == 1) { + avrdude_message(MSG_INFO, "Quell level: %d\n", quell_progress); + return 0; + } + nquell = strtol(argv[1], &endp, 0); + if (endp == argv[1] || *endp) { + avrdude_message(MSG_INFO, "%s (quell): can't parse quell level %s\n", + progname, argv[1]); + return -1; + } + if (nquell < 0) { + avrdude_message(MSG_INFO, "%s: quell level must not be negative: %d\n", + progname, nquell); + return -1; + } + quell_progress = nquell; + avrdude_message(MSG_INFO, "New quell level: %d\n", quell_progress); + + if(quell_progress > 0) + update_progress = NULL; + + return 0; +} + static int tokenize(char * s, char *** argv) { int i, n, l, k, nargs, offset; From b6204b181a3cb5167e2c41abe3dd79ae19f947c6 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 12 Jul 2022 15:22:52 +0100 Subject: [PATCH 28/38] Provide echo of terminal command line prompt under Windows --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 5050938b..fe19d2d5 100644 --- a/src/term.c +++ b/src/term.c @@ -1477,7 +1477,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return argc; } -#if 0 +#if defined(WIN32) fprintf(stdout, ">>> "); for (int i=0; i Date: Tue, 12 Jul 2022 21:53:37 +0100 Subject: [PATCH 29/38] Echo >>> terminal command line for Windows or non-libreadline --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index fe19d2d5..1f294540 100644 --- a/src/term.c +++ b/src/term.c @@ -1477,7 +1477,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return argc; } -#if defined(WIN32) +#if !defined(HAVE_LIBREADLINE) || defined(WIN32) fprintf(stdout, ">>> "); for (int i=0; i Date: Wed, 13 Jul 2022 11:19:21 +0100 Subject: [PATCH 30/38] Fix isspace() and other isxxx() calls in term.c --- src/term.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/term.c b/src/term.c index 1f294540..8cd48b99 100644 --- a/src/term.c +++ b/src/term.c @@ -124,19 +124,19 @@ static int spi_mode = 0; static int nexttok(char * buf, char ** tok, char ** next) { - char * q, * n; + unsigned char *q, *n; - q = buf; - while (isspace((int)*q)) + q = (unsigned char *) buf; + while (isspace(*q)) q++; /* isolate first token */ n = q; uint8_t quotes = 0; - while (*n && (!isspace((int)*n) || quotes)) { + while (*n && (!isspace(*n) || quotes)) { if (*n == '\"') quotes++; - else if (isspace((int)*n) && *(n-1) == '\"') + else if (isspace(*n) && *(n-1) == '\"') break; n++; } @@ -147,11 +147,11 @@ static int nexttok(char * buf, char ** tok, char ** next) } /* find start of next token */ - while (isspace((int)*n)) + while (isspace(*n)) n++; - *tok = q; - *next = n; + *tok = (char *) q; + *next = (char *) n; return 0; } @@ -190,14 +190,17 @@ static int hexdump_line(char * buffer, unsigned char * p, int n, int pad) static int chardump_line(char * buffer, unsigned char * p, int n, int pad) { int i; - char b [ 128 ]; + unsigned char b[128]; + // sanity check + n = n < 1? 1: n > sizeof b? sizeof b: n; + + memcpy(b, p, n); for (int i = 0; i < n; i++) { - memcpy(b, p, n); buffer[i] = '.'; - if (isalpha((int)(b[i])) || isdigit((int)(b[i])) || ispunct((int)(b[i]))) + if (isalpha(b[i]) || isdigit(b[i]) || ispunct(b[i])) buffer[i] = b[i]; - else if (isspace((int)(b[i]))) + else if (isspace(b[i])) buffer[i] = ' '; } @@ -344,7 +347,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, // Convert the next n hex digits of s to a hex number -static unsigned int tohex(const char *s, unsigned int n) { +static unsigned int tohex(const unsigned char *s, unsigned int n) { int ret, c; ret = 0; @@ -362,7 +365,7 @@ static unsigned int tohex(const char *s, unsigned int n) { * Permissive for some invalid unicode sequences but not for those with * high bit set). Returns numbers of characters written (0-6). */ -static int wc_to_utf8str(unsigned int wc, char *str) { +static int wc_to_utf8str(unsigned int wc, unsigned char *str) { if(!(wc & ~0x7fu)) { *str = (char) wc; return 1; @@ -406,8 +409,8 @@ static int wc_to_utf8str(unsigned int wc, char *str) { } // Unescape C-style strings, destination d must hold enough space (and can be source s) -static char *unescape(char *d, const char *s) { - char *ret = d; +static unsigned char *unescape(unsigned char *d, const unsigned char *s) { + unsigned char *ret = d; int n, k; while(*s) { @@ -650,7 +653,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Data info int bytes_grown; uint8_t size; - char * str_ptr; + char *str_ptr; // Data union union { float f; @@ -793,7 +796,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Strip start and end quotes, and unescape C string strncpy(s, argi+1, arglen-2); - unescape(s, s); + unescape((unsigned char *) s, (unsigned char *) s); if (*argi == '\'') { // Single C-style character if(*s && s[1]) avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", @@ -1463,7 +1466,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) * find the start of the command, skipping any white space */ q = cmdbuf; - while (*q && isspace((int)*q)) + while (*q && isspace((unsigned char) *q)) q++; /* skip blank lines and comments */ From 1efbc64922486a6036cce04fedc34ef514b251c5 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 13 Jul 2022 11:38:43 +0100 Subject: [PATCH 31/38] Add terminal_setup_update_progress() library interface to term.c This enables the new quell terminal command to switch on and off progress reports to the terminal. The code for this was moved from main.c to term.c. It can be used as library call for other frontends than main.c --- src/main.c | 80 ++------------------------------------------------- src/term.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/term.h | 1 + 3 files changed, 86 insertions(+), 79 deletions(-) diff --git a/src/main.c b/src/main.c index 1d00ae67..b6fd2926 100644 --- a/src/main.c +++ b/src/main.c @@ -135,72 +135,6 @@ static void usage(void) } -static void update_progress_tty (int percent, double etime, char *hdr) -{ - static char hashes[51]; - static char *header; - static int last = 0; - int i; - - setvbuf(stderr, (char*)NULL, _IONBF, 0); - - hashes[50] = 0; - - memset (hashes, ' ', 50); - for (i=0; i>1)*2; - - setvbuf(stderr, (char*)NULL, _IONBF, 0); - - if (hdr) { - avrdude_message(MSG_INFO, "\n%s | ", hdr); - last = 0; - done = 0; - } - else { - while ((cnt > last) && (done == 0)) { - avrdude_message(MSG_INFO, "#"); - cnt -= 2; - } - } - - if ((percent == 100) && (done == 0)) { - avrdude_message(MSG_INFO, " | 100%% %0.2fs\n\n", etime); - last = 0; - done = 1; - } - else - last = (percent>>1)*2; /* Make last a multiple of 2. */ - - setvbuf(stderr, (char*)NULL, _IOLBF, 0); -} - static void list_programmers_callback(const char *name, const char *desc, const char *cfgname, int cfglineno, void *cookie) @@ -759,18 +693,8 @@ int main(int argc, char * argv []) } #endif - if (quell_progress == 0) { - if (isatty (STDERR_FILENO)) - update_progress = update_progress_tty; - else { - update_progress = update_progress_no_tty; - /* disable all buffering of stderr for compatibility with - software that captures and redirects output to a GUI - i.e. Programmers Notepad */ - setvbuf( stderr, NULL, _IONBF, 0 ); - setvbuf( stdout, NULL, _IONBF, 0 ); - } - } + if (quell_progress == 0) + terminal_setup_update_progress(); /* * Print out an identifying string so folks can tell what version diff --git a/src/term.c b/src/term.c index 8cd48b99..ec95fcec 100644 --- a/src/term.c +++ b/src/term.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #if defined(HAVE_LIBREADLINE) @@ -345,7 +346,6 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } - // Convert the next n hex digits of s to a hex number static unsigned int tohex(const unsigned char *s, unsigned int n) { int ret, c; @@ -1294,6 +1294,8 @@ static int cmd_quell(PROGRAMMER * pgm, struct avrpart * p, if(quell_progress > 0) update_progress = NULL; + else + terminal_setup_update_progress(); return 0; } @@ -1499,3 +1501,83 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return rc; } + + +static void update_progress_tty (int percent, double etime, char *hdr) +{ + static char hashes[51]; + static char *header; + static int last = 0; + int i; + + setvbuf(stderr, (char*)NULL, _IONBF, 0); + + hashes[50] = 0; + + memset (hashes, ' ', 50); + for (i=0; i>1)*2; + + setvbuf(stderr, (char*)NULL, _IONBF, 0); + + if (hdr) { + avrdude_message(MSG_INFO, "\n%s | ", hdr); + last = 0; + done = 0; + } + else { + while ((cnt > last) && (done == 0)) { + avrdude_message(MSG_INFO, "#"); + cnt -= 2; + } + } + + if ((percent == 100) && (done == 0)) { + avrdude_message(MSG_INFO, " | 100%% %0.2fs\n\n", etime); + last = 0; + done = 1; + } + else + last = (percent>>1)*2; /* Make last a multiple of 2. */ + + setvbuf(stderr, (char*)NULL, _IOLBF, 0); +} + +void terminal_setup_update_progress() { + if (isatty (STDERR_FILENO)) + update_progress = update_progress_tty; + else { + update_progress = update_progress_no_tty; + /* disable all buffering of stderr for compatibility with + software that captures and redirects output to a GUI + i.e. Programmers Notepad */ + setvbuf( stderr, NULL, _IONBF, 0 ); + setvbuf( stdout, NULL, _IONBF, 0 ); + } +} diff --git a/src/term.h b/src/term.h index f114d4b0..61c4916c 100644 --- a/src/term.h +++ b/src/term.h @@ -34,6 +34,7 @@ typedef enum { int terminal_mode(PROGRAMMER * pgm, struct avrpart * p); char * terminal_get_input(const char *prompt); +void terminal_setup_update_progress(); #ifdef __cplusplus } From 0b3a5781fc46e6193b26560eed8c7a1d062cb511 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 13 Jul 2022 11:48:29 +0100 Subject: [PATCH 32/38] Flush stderr and stdout with all terminal error messages Error messages are written to stderr whilst normal terminal output is stdout. When redirecting output to pipelines or files these two streams can get separated as they are buffered separately. To avoid this, term.c now provides a function terminal_message() that works just like avrdude_message() but flushes stderr and stdout before printing on stderr, and it flushes stderr afterwards. This commit replaces all avrdude_message() calls except for progress report with terminal_message() to ensure stdout and stderr streams keep together. --- src/term.c | 155 +++++++++++++++++++++++++++++------------------------ src/term.h | 1 + 2 files changed, 87 insertions(+), 69 deletions(-) diff --git a/src/term.c b/src/term.c index ec95fcec..18999b19 100644 --- a/src/term.c +++ b/src/term.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -241,7 +242,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { if (argc < 2 || argc > 4) { - avrdude_message(MSG_INFO, + terminal_message(MSG_INFO, "Usage: %s \n" " %s ...\n" " %s \n" @@ -256,7 +257,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", + terminal_message(MSG_INFO, "%s (dump): %s memory type not defined for part %s\n", progname, memtype, p->desc); return -1; } @@ -269,11 +270,11 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, if (argc >= 3 && strcmp(argv[2], "...") != 0) { addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - avrdude_message(MSG_INFO, "%s (dump): can't parse address %s\n", + terminal_message(MSG_INFO, "%s (dump): can't parse address %s\n", progname, argv[2]); return -1; } else if (addr >= maxsize) { - avrdude_message(MSG_INFO, "%s (dump): address 0x%05lx is out of range for %s memory\n", + terminal_message(MSG_INFO, "%s (dump): address 0x%05lx is out of range for %s memory\n", progname, (long) addr, mem->desc); return -1; } @@ -290,7 +291,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, } else if (argc == 4) { len = strtol(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (dump): can't parse length %s\n", + terminal_message(MSG_INFO, "%s (dump): can't parse length %s\n", progname, argv[3]); return -1; } @@ -316,7 +317,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, uint8_t * buf = malloc(len); if (buf == NULL) { - avrdude_message(MSG_INFO, "%s (dump): out of memory\n", progname); + terminal_message(MSG_INFO, "%s (dump): out of memory\n", progname); return -1; } @@ -324,10 +325,10 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p, for (int i = 0; i < len; i++) { int rc = pgm->read_byte(pgm, p, mem, addr + i, &buf[i]); if (rc != 0) { - avrdude_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n", + terminal_message(MSG_INFO, "%s (dump): error reading %s address 0x%05lx of part %s\n", progname, mem->desc, (long) addr + i, p->desc); if (rc == -1) - avrdude_message(MSG_INFO, "%*sread operation not supported on memory type %s\n", + terminal_message(MSG_INFO, "%*sread operation not supported on memory type %s\n", (int) strlen(progname)+9, "", mem->desc); return -1; } @@ -566,7 +567,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { if (argc < 4) { - avrdude_message(MSG_INFO, + terminal_message(MSG_INFO, "Usage: write [,] {[,]} \n" " write [,] {[,]} ...\n" "\n" @@ -604,7 +605,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * memtype = argv[1]; // Memory name string AVRMEM * mem = avr_locate_mem(p, memtype); if (mem == NULL) { - avrdude_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", + terminal_message(MSG_INFO, "%s (write): %s memory type not defined for part %s\n", progname, memtype, p->desc); return -1; } @@ -613,13 +614,13 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, char * end_ptr; int addr = strtoul(argv[2], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[2])) { - avrdude_message(MSG_INFO, "%s (write): can't parse address %s\n", + terminal_message(MSG_INFO, "%s (write): can't parse address %s\n", progname, argv[2]); return -1; } if (addr > maxsize) { - avrdude_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n", + terminal_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n", progname, (long) addr, memtype); return -1; } @@ -627,7 +628,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, // Allocate a buffer guaranteed to be large enough uint8_t * buf = calloc(mem->size + 0x10 + maxstrlen(argc-3, argv+3), sizeof(uint8_t)); if (buf == NULL) { - avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname); + terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); return -1; } @@ -637,7 +638,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, start_offset = 4; len = strtoul(argv[3], &end_ptr, 0); if (*end_ptr || (end_ptr == argv[3])) { - avrdude_message(MSG_INFO, "%s (write ...): can't parse length %s\n", + terminal_message(MSG_INFO, "%s (write ...): can't parse length %s\n", progname, argv[3]); free(buf); return -1; @@ -670,7 +671,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, }; if(sizeof(long long) != sizeof(int64_t) || (data.a[0]^data.a[7]) != 1) - avrdude_message(MSG_INFO, "%s (write): assumption on data types not met? " + terminal_message(MSG_INFO, "%s (write): assumption on data types not met? " "Check source and recompile\n", progname); bool is_big_endian = data.a[7]; @@ -765,7 +766,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } if(is_outside_int64_t || is_out_of_range) - avrdude_message(MSG_INFO, "%s (write): %s out of int%d_t range, " + terminal_message(MSG_INFO, "%s (write): %s out of int%d_t range, " "interpreted as %d-byte %lld; consider 'U' suffix\n", progname, argi, data.size*8, data.size, data.ll); } @@ -790,7 +791,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { char *s = calloc(arglen-1, 1); if (s == NULL) { - avrdude_message(MSG_INFO, "%s (write str): out of memory\n", progname); + terminal_message(MSG_INFO, "%s (write str): out of memory\n", progname); free(buf); return -1; } @@ -799,7 +800,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, unescape((unsigned char *) s, (unsigned char *) s); if (*argi == '\'') { // Single C-style character if(*s && s[1]) - avrdude_message(MSG_INFO, "%s (write): only using first character of %s\n", + terminal_message(MSG_INFO, "%s (write): only using first character of %s\n", progname, argi); data.ll = *s; data.size = 1; @@ -811,7 +812,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } if(!data.size && !data.str_ptr) { - avrdude_message(MSG_INFO, "%s (write): can't parse data %s\n", + terminal_message(MSG_INFO, "%s (write): can't parse data %s\n", progname, argi); free(buf); return -1; @@ -851,7 +852,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.bytes_grown = 0; if ((addr + len + data.bytes_grown) > maxsize) { - avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed " + terminal_message(MSG_INFO, "%s (write): selected address and # bytes exceed " "range for %s memory\n", progname, memtype); free(buf); return -1; @@ -860,11 +861,11 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(data.str_ptr) free(data.str_ptr); - avrdude_message(MSG_NOTICE, "Info: writing %d bytes starting from address 0x%02lx", + terminal_message(MSG_NOTICE, "Info: writing %d bytes starting from address 0x%02lx", len + data.bytes_grown, (long) addr); if (write_mode == WRITE_MODE_FILL) - avrdude_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]); - avrdude_message(MSG_NOTICE, "\n"); + terminal_message(MSG_NOTICE, "; remaining space filled with %s", argv[argc - 2]); + terminal_message(MSG_NOTICE, "\n"); pgm->err_led(pgm, OFF); bool werror = false; @@ -872,10 +873,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, for (i = 0; i < (len + data.bytes_grown); i++) { int rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]); if (rc) { - avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", + terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n", progname, buf[i], (long) addr+i, (int) rc); if (rc == -1) - avrdude_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n", + terminal_message(MSG_INFO, "%*swrite operation not supported on memory type %s\n", (int) strlen(progname)+10, "", mem->desc); werror = true; } @@ -883,7 +884,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, uint8_t b; rc = pgm->read_byte(pgm, p, mem, addr+i, &b); if (b != buf[i]) { - avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n", + terminal_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n", progname, buf[i], (long) addr+i, b); werror = true; } @@ -911,20 +912,20 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p, int len; if (pgm->cmd == NULL) { - avrdude_message(MSG_INFO, "%s (send): the %s programmer does not support direct ISP commands\n", + terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct ISP commands\n", progname, pgm->type); return -1; } if (spi_mode && (pgm->spi == NULL)) { - avrdude_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", + terminal_message(MSG_INFO, "%s (send): the %s programmer does not support direct SPI transfers\n", progname, pgm->type); return -1; } if ((argc > 5) || ((argc < 5) && (!spi_mode))) { - avrdude_message(MSG_INFO, spi_mode? + terminal_message(MSG_INFO, spi_mode? "Usage: send [ [ []]]\n": "Usage: send \n"); return -1; @@ -937,7 +938,7 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p, for (i=1; ichip_erase(pgm, p); return 0; } @@ -993,13 +994,13 @@ static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p, rc = avr_signature(pgm, p); if (rc != 0) { - avrdude_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n", + terminal_message(MSG_INFO, "%s (sig): error reading signature data, rc=%d\n", progname, rc); } m = avr_locate_mem(p, "signature"); if (m == NULL) { - avrdude_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n", + terminal_message(MSG_INFO, "%s (sig): signature data not defined for device %s\n", progname, p->desc); } else { @@ -1028,7 +1029,7 @@ static int cmd_parms(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { if (pgm->print_parms == NULL) { - avrdude_message(MSG_INFO, "%s (parms): the %s programmer does not support " + terminal_message(MSG_INFO, "%s (parms): the %s programmer does not support " "adjustable parameters\n", progname, pgm->type); return -1; } @@ -1046,22 +1047,22 @@ static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 2) { - avrdude_message(MSG_INFO, "Usage: vtarg \n"); + terminal_message(MSG_INFO, "Usage: vtarg \n"); return -1; } v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n", + terminal_message(MSG_INFO, "%s (vtarg): can't parse voltage %s\n", progname, argv[1]); return -1; } if (pgm->set_vtarget == NULL) { - avrdude_message(MSG_INFO, "%s (vtarg): the %s programmer cannot set V[target]\n", + terminal_message(MSG_INFO, "%s (vtarg): the %s programmer cannot set V[target]\n", progname, pgm->type); return -2; } if ((rc = pgm->set_vtarget(pgm, v)) != 0) { - avrdude_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n", + terminal_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n", progname, rc); return -3; } @@ -1077,7 +1078,7 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 2) { - avrdude_message(MSG_INFO, "Usage: fosc [M|k] | off\n"); + terminal_message(MSG_INFO, "Usage: fosc [M|k] | off\n"); return -1; } v = strtod(argv[1], &endp); @@ -1085,7 +1086,7 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, if (strcmp(argv[1], "off") == 0) v = 0.0; else { - avrdude_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n", + terminal_message(MSG_INFO, "%s (fosc): can't parse frequency %s\n", progname, argv[1]); return -1; } @@ -1095,12 +1096,12 @@ static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p, else if (*endp == 'k' || *endp == 'K') v *= 1e3; if (pgm->set_fosc == NULL) { - avrdude_message(MSG_INFO, "%s (fosc): the %s programmer cannot set oscillator frequency\n", + terminal_message(MSG_INFO, "%s (fosc): the %s programmer cannot set oscillator frequency\n", progname, pgm->type); return -2; } if ((rc = pgm->set_fosc(pgm, v)) != 0) { - avrdude_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n", + terminal_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n", progname, rc); return -3; } @@ -1116,23 +1117,23 @@ static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 2) { - avrdude_message(MSG_INFO, "Usage: sck \n"); + terminal_message(MSG_INFO, "Usage: sck \n"); return -1; } v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (sck): can't parse period %s\n", + terminal_message(MSG_INFO, "%s (sck): can't parse period %s\n", progname, argv[1]); return -1; } v *= 1e-6; /* Convert from microseconds to seconds. */ if (pgm->set_sck_period == NULL) { - avrdude_message(MSG_INFO, "%s (sck): the %s programmer cannot set SCK period\n", + terminal_message(MSG_INFO, "%s (sck): the %s programmer cannot set SCK period\n", progname, pgm->type); return -2; } if ((rc = pgm->set_sck_period(pgm, v)) != 0) { - avrdude_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n", + terminal_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n", progname, rc); return -3; } @@ -1149,38 +1150,38 @@ static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 2 && argc != 3) { - avrdude_message(MSG_INFO, "Usage: varef [channel] \n"); + terminal_message(MSG_INFO, "Usage: varef [channel] \n"); return -1; } if (argc == 2) { chan = 0; v = strtod(argv[1], &endp); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", + terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", progname, argv[1]); return -1; } } else { chan = strtoul(argv[1], &endp, 10); if (endp == argv[1]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse channel %s\n", + terminal_message(MSG_INFO, "%s (varef): can't parse channel %s\n", progname, argv[1]); return -1; } v = strtod(argv[2], &endp); if (endp == argv[2]) { - avrdude_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", + terminal_message(MSG_INFO, "%s (varef): can't parse voltage %s\n", progname, argv[2]); return -1; } } if (pgm->set_varef == NULL) { - avrdude_message(MSG_INFO, "%s (varef): the %s programmer cannot set V[aref]\n", + terminal_message(MSG_INFO, "%s (varef): the %s programmer cannot set V[aref]\n", progname, pgm->type); return -2; } if ((rc = pgm->set_varef(pgm, chan, v)) != 0) { - avrdude_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n", + terminal_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n", progname, rc); return -3; } @@ -1214,7 +1215,7 @@ static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p, spi_mode = 1; return 0; } - avrdude_message(MSG_INFO, "%s: spi command unavailable for this programmer type\n", + terminal_message(MSG_INFO, "%s: spi command unavailable for this programmer type\n", progname); return -1; } @@ -1228,7 +1229,7 @@ static int cmd_pgm(PROGRAMMER * pgm, struct avrpart * p, pgm->initialize(pgm, p); return 0; } - avrdude_message(MSG_INFO, "%s: pgm command unavailable for this programmer type\n", + terminal_message(MSG_INFO, "%s: pgm command unavailable for this programmer type\n", progname); return -1; } @@ -1240,26 +1241,26 @@ static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 1 && argc != 2) { - avrdude_message(MSG_INFO, "Usage: verbose []\n"); + terminal_message(MSG_INFO, "Usage: verbose []\n"); return -1; } if (argc == 1) { - avrdude_message(MSG_INFO, "Verbosity level: %d\n", verbose); + terminal_message(MSG_INFO, "Verbosity level: %d\n", verbose); return 0; } nverb = strtol(argv[1], &endp, 0); if (endp == argv[1] || *endp) { - avrdude_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n", + terminal_message(MSG_INFO, "%s (verbose): can't parse verbosity level %s\n", progname, argv[1]); return -1; } if (nverb < 0) { - avrdude_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n", + terminal_message(MSG_INFO, "%s: verbosity level must not be negative: %d\n", progname, nverb); return -1; } verbose = nverb; - avrdude_message(MSG_INFO, "New verbosity level: %d\n", verbose); + terminal_message(MSG_INFO, "New verbosity level: %d\n", verbose); return 0; } @@ -1271,26 +1272,26 @@ static int cmd_quell(PROGRAMMER * pgm, struct avrpart * p, char *endp; if (argc != 1 && argc != 2) { - avrdude_message(MSG_INFO, "Usage: quell []\n"); + terminal_message(MSG_INFO, "Usage: quell []\n"); return -1; } if (argc == 1) { - avrdude_message(MSG_INFO, "Quell level: %d\n", quell_progress); + terminal_message(MSG_INFO, "Quell level: %d\n", quell_progress); return 0; } nquell = strtol(argv[1], &endp, 0); if (endp == argv[1] || *endp) { - avrdude_message(MSG_INFO, "%s (quell): can't parse quell level %s\n", + terminal_message(MSG_INFO, "%s (quell): can't parse quell level %s\n", progname, argv[1]); return -1; } if (nquell < 0) { - avrdude_message(MSG_INFO, "%s: quell level must not be negative: %d\n", + terminal_message(MSG_INFO, "%s: quell level must not be negative: %d\n", progname, nquell); return -1; } quell_progress = nquell; - avrdude_message(MSG_INFO, "New quell level: %d\n", quell_progress); + terminal_message(MSG_INFO, "New quell level: %d\n", quell_progress); if(quell_progress > 0) update_progress = NULL; @@ -1413,7 +1414,7 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p, } else if (strncasecmp(argv[0], cmd[i].name, len)==0) { if (hold != -1) { - avrdude_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", + terminal_message(MSG_INFO, "%s (cmd): command %s is ambiguous\n", progname, argv[0]); return -1; } @@ -1424,7 +1425,7 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p, if (hold != -1) return cmd[hold].func(pgm, p, argc, argv); - avrdude_message(MSG_INFO, "%s (cmd): invalid command %s\n", + terminal_message(MSG_INFO, "%s (cmd): invalid command %s\n", progname, argv[0]); return -1; @@ -1503,6 +1504,22 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) } +int terminal_message(const int msglvl, const char *format, ...) { + int rc = 0; + va_list ap; + + fflush(stdout); fflush(stderr); + if (verbose >= msglvl) { + va_start(ap, format); + rc = vfprintf(stderr, format, ap); + va_end(ap); + } + fflush(stderr); + + return rc; +} + + static void update_progress_tty (int percent, double etime, char *hdr) { static char hashes[51]; diff --git a/src/term.h b/src/term.h index 61c4916c..a89927ea 100644 --- a/src/term.h +++ b/src/term.h @@ -35,6 +35,7 @@ typedef enum { int terminal_mode(PROGRAMMER * pgm, struct avrpart * p); char * terminal_get_input(const char *prompt); void terminal_setup_update_progress(); +int terminal_message(const int msglvl, const char *format, ...); #ifdef __cplusplus } From b02cce38d76346a4dcef69717fbe77e530bea261 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Wed, 13 Jul 2022 12:25:09 +0100 Subject: [PATCH 33/38] Added long double data type for terminal write --- src/term.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/term.c b/src/term.c index 18999b19..96abbf7c 100644 --- a/src/term.c +++ b/src/term.c @@ -626,7 +626,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Allocate a buffer guaranteed to be large enough - uint8_t * buf = calloc(mem->size + 0x10 + maxstrlen(argc-3, argv+3), sizeof(uint8_t)); + uint8_t * buf = calloc(mem->size + sizeof(long double) + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); if (buf == NULL) { terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); return -1; @@ -659,9 +659,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, union { float f; double d; + long double ld; int64_t ll; uint64_t ull; - uint8_t a[8]; + uint8_t a[sizeof(long double) > 8? sizeof(long double): 8]; }; } data = { .bytes_grown = 0, @@ -773,7 +774,13 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } - if(!data.size) { // Try double now that input was rejected as integer + if(!data.size) { // Try long double now that input was rejected as integer + data.ld = strtold(argi, &end_ptr); + if (end_ptr != argi && toupper(*end_ptr) == 'L' && end_ptr[1] == 0) + data.size = sizeof(data.ld); + } + + if(!data.size) { // Try double data.d = strtod(argi, &end_ptr); // Do not accept valid mantissa-only doubles that are integer rejects (eg, 078 or ULL overflows) if (end_ptr != argi && *end_ptr == 0) @@ -826,20 +833,10 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, if(data.str_ptr) { for(size_t j = 0; j < strlen(data.str_ptr); j++) buf[i - start_offset + data.bytes_grown++] = (uint8_t)data.str_ptr[j]; - } else { - buf[i - start_offset + data.bytes_grown] = data.a[0]; - if (llabs(data.ll) > 0x000000FF || data.size >= 2) - buf[i - start_offset + ++data.bytes_grown] = data.a[1]; - if (llabs(data.ll) > 0x0000FFFF || data.size >= 4) { - buf[i - start_offset + ++data.bytes_grown] = data.a[2]; - buf[i - start_offset + ++data.bytes_grown] = data.a[3]; - } - if (llabs(data.ll) > 0xFFFFFFFF || data.size == 8) { - buf[i - start_offset + ++data.bytes_grown] = data.a[4]; - buf[i - start_offset + ++data.bytes_grown] = data.a[5]; - buf[i - start_offset + ++data.bytes_grown] = data.a[6]; - buf[i - start_offset + ++data.bytes_grown] = data.a[7]; - } + } else if(data.size > 0) { + for(int k=0; k Date: Wed, 13 Jul 2022 12:35:49 +0100 Subject: [PATCH 34/38] Change terminal write usage message to accommodate long double --- src/term.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/term.c b/src/term.c index 96abbf7c..ea34d5ee 100644 --- a/src/term.c +++ b/src/term.c @@ -574,11 +574,12 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, "Ellipsis ... writes bytes padded by repeating the last item.\n" "\n" " can be hexadecimal, octal or decimal integers, double, float or\n" - "C-style strings and chars. For numbers, an optional case-insensitive suffix\n" - "specifies the data size: HH: 8 bit, H/S: 16 bit, L: 32 bit, LL: 64 bit, F:\n" - "32-bit float. Hexadecimal floating point notation is supported. The\n" - "ambiguous trailing F in 0x1.8F makes the number be interpreted as double;\n" - "use a zero exponent as in 0x1.8p0F to denote a hexadecimal float.\n" + "C-style strings and chars. For integers, an optional case-insensitive suffix\n" + "specifies the data size: HH: 8 bit, H/S: 16 bit, L: 32 bit or LL: 64 bit.\n" + "Floating point types follow the C convention (add F for 32-bit float or L for\n" + "long double). Hexadecimal floating point notation is supported. The ambiguous\n" + "trailing F in 0x1.8F makes the number be interpreted as double; use a zero\n" + "exponent as in 0x1.8p0F to denote a hexadecimal float.\n" "\n" "An optional U suffix makes a number unsigned. Ordinary 0x hex numbers are\n" "always treated as unsigned. +0x or -0x hex numbers are treated as signed\n" From 5721908e63a16ce44b326738c91ec4c46078b47e Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 14 Jul 2022 17:13:13 +0100 Subject: [PATCH 35/38] Revert to double/float only in terminal write and clarify usage --- src/term.c | 52 ++++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/term.c b/src/term.c index ea34d5ee..52906f29 100644 --- a/src/term.c +++ b/src/term.c @@ -573,15 +573,16 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, "\n" "Ellipsis ... writes bytes padded by repeating the last item.\n" "\n" - " can be hexadecimal, octal or decimal integers, double, float or\n" - "C-style strings and chars. For integers, an optional case-insensitive suffix\n" - "specifies the data size: HH: 8 bit, H/S: 16 bit, L: 32 bit or LL: 64 bit.\n" - "Floating point types follow the C convention (add F for 32-bit float or L for\n" - "long double). Hexadecimal floating point notation is supported. The ambiguous\n" - "trailing F in 0x1.8F makes the number be interpreted as double; use a zero\n" - "exponent as in 0x1.8p0F to denote a hexadecimal float.\n" + " can be hexadecimal, octal or decimal integers, floating point numbers\n" + "or C-style strings and characters. For integers, an optional case-insensitive\n" + "suffix specifies the data size: HH 8 bit, H/S 16 bit, L 32 bit, LL 64 bit.\n" + "Suffix D indicates a 64-bit double, F a 32-bit float, whilst a floating point\n" + "number without suffix defaults to 32-bit float. Hexadecimal floating point\n" + "notation is supported. An ambiguous trailing suffix, eg, 0x1.8D, is read as\n" + "no-suffix float where D is part of the mantissa; use a zero exponent 0x1.8p0D\n" + "to clarify.\n" "\n" - "An optional U suffix makes a number unsigned. Ordinary 0x hex numbers are\n" + "An optional U suffix makes integers unsigned. Ordinary 0x hex integers are\n" "always treated as unsigned. +0x or -0x hex numbers are treated as signed\n" "unless they have a U suffix. Unsigned integers cannot be larger than 2^64-1.\n" "If n is an unsigned integer then -n is also a valid unsigned integer as in C.\n" @@ -589,12 +590,12 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, "smaller range when a suffix specifies a smaller type. Out of range signed\n" "numbers trigger a warning.\n" "\n" - "Ordinary 0x hex numbers with n hex digits (counting leading zeros) use\n" - "the smallest size of 1, 2, 4 and 8 bytes that can accommodate any n-digit hex\n" - "number. If a suffix specifies a size explicitly the corresponding number of\n" - "least significant bytes are written. Otherwise, signed and unsigned integers\n" - "alike occupy the smallest of 1, 2, 4, or 8 bytes needed to accommodate them\n" - "in their respective representation.\n" + "Ordinary 0x hex integers with n hex digits (counting leading zeros) use the\n" + "smallest size of 1, 2, 4 and 8 bytes that can accommodate any n-digit hex\n" + "integer. If an integer suffix specifies a size explicitly the corresponding\n" + "number of least significant bytes are written. Otherwise, signed and unsigned\n" + "integers alike occupy the smallest of 1, 2, 4, or 8 bytes needed to\n" + "accommodate them in their respective representation.\n" ); return -1; } @@ -627,7 +628,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } // Allocate a buffer guaranteed to be large enough - uint8_t * buf = calloc(mem->size + sizeof(long double) + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); + uint8_t * buf = calloc(mem->size + 8 + maxstrlen(argc-3, argv+3)+1, sizeof(uint8_t)); if (buf == NULL) { terminal_message(MSG_INFO, "%s (write): out of memory\n", progname); return -1; @@ -660,10 +661,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, union { float f; double d; - long double ld; int64_t ll; uint64_t ull; - uint8_t a[sizeof(long double) > 8? sizeof(long double): 8]; + uint8_t a[8]; }; } data = { .bytes_grown = 0, @@ -775,24 +775,20 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, } } - if(!data.size) { // Try long double now that input was rejected as integer - data.ld = strtold(argi, &end_ptr); - if (end_ptr != argi && toupper(*end_ptr) == 'L' && end_ptr[1] == 0) - data.size = sizeof(data.ld); - } - - if(!data.size) { // Try double + if(!data.size) { // Try double now that input was rejected as integer data.d = strtod(argi, &end_ptr); - // Do not accept valid mantissa-only doubles that are integer rejects (eg, 078 or ULL overflows) - if (end_ptr != argi && *end_ptr == 0) - if (!is_mantissa_only(argi)) - data.size = 8; + if (end_ptr != argi && toupper(*end_ptr) == 'D' && end_ptr[1] == 0) + data.size = 8; } if(!data.size) { // Try float data.f = strtof(argi, &end_ptr); if (end_ptr != argi && toupper(*end_ptr) == 'F' && end_ptr[1] == 0) data.size = 4; + if (end_ptr != argi && *end_ptr == 0) // no suffix defaults to float but ... + // ... do not accept valid mantissa-only floats that are integer rejects (eg, 078 or ULL overflows) + if (!is_mantissa_only(argi)) + data.size = 4; } if(!data.size) { // Try C-style string or single character From 14b27726d4fa05d7d18dcc8711d50f63e67571f3 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 14 Jul 2022 17:16:30 +0100 Subject: [PATCH 36/38] Protect terminal dump from vagaries of C libray implementation of isalpha() etc Some C libraries assign true to isalpha(0xff), isdigit(0xff) or ispunct(0xff), which means that the Operating System terminal sees a character 0xff which it may not have a useful display character for. This commit only outputs printable ASCII characters for an AVRDUDE terminal dump reducing the risk of the OS terminal not being able to print the character properly. --- src/term.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/term.c b/src/term.c index 52906f29..7fe6246c 100644 --- a/src/term.c +++ b/src/term.c @@ -198,13 +198,9 @@ static int chardump_line(char * buffer, unsigned char * p, int n, int pad) n = n < 1? 1: n > sizeof b? sizeof b: n; memcpy(b, p, n); - for (int i = 0; i < n; i++) { - buffer[i] = '.'; - if (isalpha(b[i]) || isdigit(b[i]) || ispunct(b[i])) - buffer[i] = b[i]; - else if (isspace(b[i])) - buffer[i] = ' '; - } + for (int i = 0; i < n; i++) + buffer[i] = isascii(b[i]) && isspace(b[i])? ' ': + isascii(b[i]) && isgraph(b[i])? b[i]: '.'; for (i = n; i < pad; i++) buffer[i] = ' '; From 7ceb163cbabda069462fcd4e7770ece0f5d09494 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Thu, 14 Jul 2022 18:31:44 +0100 Subject: [PATCH 37/38] Echo terminal command line on Apple --- src/term.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/term.c b/src/term.c index 7fe6246c..e779f84a 100644 --- a/src/term.c +++ b/src/term.c @@ -1473,7 +1473,7 @@ int terminal_mode(PROGRAMMER * pgm, struct avrpart * p) return argc; } -#if !defined(HAVE_LIBREADLINE) || defined(WIN32) +#if !defined(HAVE_LIBREADLINE) || defined(WIN32) || defined(__APPLE__) fprintf(stdout, ">>> "); for (int i=0; i Date: Fri, 15 Jul 2022 18:50:20 +0100 Subject: [PATCH 38/38] Fix terminal line parsing for strings (to some extent) --- src/term.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/term.c b/src/term.c index e779f84a..f02f95c5 100644 --- a/src/term.c +++ b/src/term.c @@ -136,9 +136,12 @@ static int nexttok(char * buf, char ** tok, char ** next) n = q; uint8_t quotes = 0; while (*n && (!isspace(*n) || quotes)) { - if (*n == '\"') + // poor man's quote and escape processing + if (*n == '"' || *n == '\'') quotes++; - else if (isspace(*n) && *(n-1) == '\"') + else if(*n == '\\' && n[1]) + n++; + else if (isspace(*n) && (n > q+1) && (n[-1] == '"' || n[-1] == '\'')) break; n++; } @@ -787,7 +790,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p, data.size = 4; } - if(!data.size) { // Try C-style string or single character + if(!data.size && arglen > 1) { // Try C-style string or single character if ((*argi == '\'' && argi[arglen-1] == '\'') || (*argi == '\"' && argi[arglen-1] == '\"')) { char *s = calloc(arglen-1, 1); if (s == NULL) {