[2.0.x] Buffer overflow and scroll fix, UTF8 cleanup (#10844)

This commit is contained in:
Eduardo José Tagle
2018-05-26 01:32:37 -03:00
committed by Scott Lahteine
parent 235facd545
commit 6f330f397e
17 changed files with 413 additions and 671 deletions

View File

@ -347,26 +347,51 @@ void lcd_implementation_clear() { lcd.clear(); }
}
// Scroll the PSTR 'text' in a 'len' wide field for 'time' milliseconds at position col,line
void lcd_scroll(const int16_t col, const int16_t line, const char* const text, const int16_t len, const int16_t time) {
#if 1
lcd_put_u8str(text);
#else
char tmp[LCD_WIDTH + 1] = {0};
int16_t n = MAX(utf8_strlen_P(text) - len, 0);
for (int16_t i = 0; i <= n; i++) {
utf8_strncpy_p(tmp, text + i, MIN(len, LCD_WIDTH));
lcd_moveto(col, line);
lcd_put_u8str(tmp);
delay(time / MAX(n, 1));
void lcd_scroll(const uint8_t col, const uint8_t line, const char* const text, const uint8_t len, const int16_t time) {
uint8_t slen = utf8_strlen_P(text);
if (slen < len) {
// Fits into,
lcd_moveto(col, line);
lcd_put_u8str_max_P(text, len);
while (slen < len) {
lcd_put_wchar(' ');
++slen;
}
#endif
safe_delay(time);
}
else {
const char* p = text;
int dly = time / MAX(slen, 1);
for (uint8_t i = 0; i <= slen; i++) {
// Go to the correct place
lcd_moveto(col, line);
// Print the text
lcd_put_u8str_max_P(p, len);
// Fill with spaces
uint8_t ix = slen - i;
while (ix < len) {
lcd_put_wchar(' ');
++ix;
}
// Delay
safe_delay(dly);
// Advance to the next UTF8 valid position
p++;
while (!START_OF_UTF8_CHAR(pgm_read_byte(p))) p++;
}
}
}
static void logo_lines(const char* const extra) {
int16_t indent = (LCD_WIDTH - 8 - utf8_strlen_P(extra)) / 2;
lcd_moveto(indent, 0); lcd_put_wchar('\x00'); lcd_put_u8str_rom(PSTR( "------" )); lcd_put_wchar('\x01');
lcd_moveto(indent, 1); lcd_put_u8str_rom(PSTR("|Marlin|")); lcd_put_u8str_rom(extra);
lcd_moveto(indent, 2); lcd_put_wchar('\x02'); lcd_put_u8str_rom(PSTR( "------" )); lcd_put_wchar('\x03');
lcd_moveto(indent, 0); lcd_put_wchar('\x00'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x01');
lcd_moveto(indent, 1); lcd_put_u8str_P(PSTR("|Marlin|")); lcd_put_u8str_P(extra);
lcd_moveto(indent, 2); lcd_put_wchar('\x02'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x03');
}
void lcd_bootscreen() {
@ -379,7 +404,7 @@ void lcd_implementation_clear() { lcd.clear(); }
lcd_erase_line(3); \
if (utf8_strlen(STRING) <= LCD_WIDTH) { \
lcd_moveto((LCD_WIDTH - utf8_strlen_P(PSTR(STRING))) / 2, 3); \
lcd_put_u8str_rom(PSTR(STRING)); \
lcd_put_u8str_P(PSTR(STRING)); \
safe_delay(DELAY); \
} \
else { \
@ -452,10 +477,10 @@ void lcd_kill_screen() {
lcd_moveto(0, 2);
#else
lcd_moveto(0, 2);
lcd_put_u8str_rom(PSTR(MSG_HALTED));
lcd_put_u8str_P(PSTR(MSG_HALTED));
lcd_moveto(0, 3);
#endif
lcd_put_u8str_rom(PSTR(MSG_PLEASE_RESET));
lcd_put_u8str_P(PSTR(MSG_PLEASE_RESET));
}
//
@ -473,7 +498,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
else {
#if DISABLED(HOME_AFTER_DEACTIVATE) && DISABLED(DISABLE_REDUCED_ACCURACY_WARNING)
if (!axis_known_position[axis])
lcd_put_u8str_rom(axis == Z_AXIS ? PSTR(" ") : PSTR(" "));
lcd_put_u8str_P(axis == Z_AXIS ? PSTR(" ") : PSTR(" "));
else
#endif
lcd_put_u8str(value);
@ -634,11 +659,11 @@ static void lcd_implementation_status_screen() {
#if ENABLED(SDSUPPORT)
lcd_moveto(0, 2);
lcd_put_u8str_rom(PSTR("SD"));
lcd_put_u8str_P(PSTR("SD"));
if (IS_SD_PRINTING)
lcd_put_u8str(itostr3(card.percentDone()));
else
lcd_put_u8str_rom(PSTR("---"));
lcd_put_u8str_P(PSTR("---"));
lcd_put_wchar('%');
#endif // SDSUPPORT
@ -698,11 +723,11 @@ static void lcd_implementation_status_screen() {
#if LCD_WIDTH >= 20 && ENABLED(SDSUPPORT)
lcd_moveto(7, 2);
lcd_put_u8str_rom(PSTR("SD"));
lcd_put_u8str_P(PSTR("SD"));
if (IS_SD_PRINTING)
lcd_put_u8str(itostr3(card.percentDone()));
else
lcd_put_u8str_rom(PSTR("---"));
lcd_put_u8str_P(PSTR("---"));
lcd_put_wchar('%');
#endif // LCD_WIDTH >= 20 && SDSUPPORT
@ -739,9 +764,9 @@ static void lcd_implementation_status_screen() {
// Show Filament Diameter and Volumetric Multiplier %
// After allowing lcd_status_message to show for 5 seconds
if (ELAPSED(millis(), previous_lcd_status_ms + 5000UL)) {
lcd_put_u8str_rom(PSTR("Dia "));
lcd_put_u8str_P(PSTR("Dia "));
lcd_put_u8str(ftostr12ns(filament_width_meas));
lcd_put_u8str_rom(PSTR(" V"));
lcd_put_u8str_P(PSTR(" V"));
lcd_put_u8str(itostr3(100.0 * (
parser.volumetric_enabled
? planner.volumetric_area_nominal / planner.volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]
@ -756,35 +781,76 @@ static void lcd_implementation_status_screen() {
#if ENABLED(STATUS_MESSAGE_SCROLLING)
static bool last_blink = false;
const uint8_t slen = utf8_strlen(lcd_status_message);
const char *stat = lcd_status_message + status_scroll_pos;
if (slen <= LCD_WIDTH)
lcd_put_u8str(stat); // The string isn't scrolling
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(lcd_status_message);
// If the string fits into the LCD, just print it and do not scroll it
if (slen <= LCD_WIDTH) {
// The string isn't scrolling and may not fill the screen
lcd_put_u8str(lcd_status_message);
// Fill the rest with spaces
while (slen < LCD_WIDTH) {
lcd_put_wchar(' ');
++slen;
}
}
else {
if (status_scroll_pos <= slen - LCD_WIDTH)
lcd_put_u8str(stat); // The string fills the screen
// String is larger than the available space in screen.
// Get a pointer to the next valid UTF8 character
const char *stat = lcd_status_message + status_scroll_offset;
// Get the string remaining length
const uint8_t rlen = utf8_strlen(stat);
// If we have enough characters to display
if (rlen >= LCD_WIDTH) {
// The remaining string fills the screen - Print it
lcd_put_u8str_max(stat, LCD_WIDTH);
}
else {
uint8_t chars = LCD_WIDTH;
if (status_scroll_pos < slen) { // First string still visible
lcd_put_u8str(stat); // The string leaves space
chars -= slen - status_scroll_pos; // Amount of space left
}
lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot
if (--chars) {
if (status_scroll_pos < slen + 1) // Draw a second dot if there's space
--chars, lcd_put_wchar('.');
if (chars) lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message
// The remaining string does not completely fill the screen
lcd_put_u8str_max(stat, LCD_WIDTH); // The string leaves space
uint8_t chars = LCD_WIDTH - rlen; // Amount of space left in characters
lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot
if (--chars) { // Draw a second dot if there's space
lcd_put_wchar('.');
if (--chars)
lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message
}
}
if (last_blink != blink) {
last_blink = blink;
// Skip any non-printing bytes
if (status_scroll_pos < slen) while (!PRINTABLE(lcd_status_message[status_scroll_pos])) status_scroll_pos++;
if (++status_scroll_pos >= slen + 2) status_scroll_pos = 0;
// Adjust by complete UTF8 characters
if (status_scroll_offset < slen) {
status_scroll_offset++;
while (!START_OF_UTF8_CHAR(lcd_status_message[status_scroll_offset]))
status_scroll_offset++;
}
else
status_scroll_offset = 0;
}
}
#else
lcd_put_u8str(lcd_status_message);
UNUSED(blink);
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(lcd_status_message);
// Just print the string to the LCD
lcd_put_u8str_max(lcd_status_message, LCD_WIDTH);
// Fill the rest with spaces if there are missing spaces
while (slen < LCD_WIDTH) {
lcd_put_wchar(' ');
++slen;
}
#endif
}
@ -809,7 +875,7 @@ static void lcd_implementation_status_screen() {
int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2;
while (--pad >= 0) { lcd_put_wchar(' '); n--; }
}
n -= lcd_put_u8str_max_rom(pstr, n);
n -= lcd_put_u8str_max_P(pstr, n);
if (valstr) n -= lcd_put_u8str_max(valstr, n);
for (; n > 0; --n) lcd_put_wchar(' ');
}
@ -818,7 +884,7 @@ static void lcd_implementation_status_screen() {
uint8_t n = LCD_WIDTH - 2;
lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' ');
n -= lcd_put_u8str_max_rom(pstr, n);
n -= lcd_put_u8str_max_P(pstr, n);
while (n--) lcd_put_wchar(' ');
lcd_put_wchar(post_char);
}
@ -827,7 +893,7 @@ static void lcd_implementation_status_screen() {
uint8_t n = LCD_WIDTH - 2 - utf8_strlen(data);
lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' ');
n -= lcd_put_u8str_max_rom(pstr, n);
n -= lcd_put_u8str_max_P(pstr, n);
lcd_put_wchar(':');
while (n--) lcd_put_wchar(' ');
lcd_put_u8str(data);
@ -836,10 +902,10 @@ static void lcd_implementation_status_screen() {
uint8_t n = LCD_WIDTH - 2 - utf8_strlen_P(data);
lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' ');
n -= lcd_put_u8str_max_rom(pstr, n);
n -= lcd_put_u8str_max_P(pstr, n);
lcd_put_wchar(':');
while (n--) lcd_put_wchar(' ');
lcd_put_u8str_rom(data);
lcd_put_u8str_P(data);
}
#define DRAWMENU_SETTING_EDIT_GENERIC(_src) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', _src)
@ -847,7 +913,7 @@ static void lcd_implementation_status_screen() {
void lcd_implementation_drawedit(const char* pstr, const char* const value=NULL) {
lcd_moveto(1, 1);
lcd_put_u8str_rom(pstr);
lcd_put_u8str_P(pstr);
if (value != NULL) {
lcd_put_wchar(':');
int len = utf8_strlen(value);
@ -1293,7 +1359,7 @@ static void lcd_implementation_status_screen() {
if (!isnan(ubl.z_values[x][inverted_y]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y]));
else
lcd_put_u8str_rom(PSTR(" -----"));
lcd_put_u8str_P(PSTR(" -----"));
#else // 16x4 or 20x4 display
@ -1312,7 +1378,7 @@ static void lcd_implementation_status_screen() {
if (!isnan(ubl.z_values[x][inverted_y]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y]));
else
lcd_put_u8str_rom(PSTR(" -----"));
lcd_put_u8str_P(PSTR(" -----"));
#endif // LCD_HEIGHT > 3
}