auxdisplay: charlcd: Fix and clean up handling of x/y commands
The current version is not parsing multiple x/y commands as the code originally intended. On top of that, kstrtoul() expects NULL-terminated strings. Finally, the code does two passes over the string. Some explanations about the supported syntax are added as well. Cc: Willy Tarreau <w@1wt.eu> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Andy Shevchenko <andy.shevchenko@gmail.com> Cc: Robert Abel <rabel@robertabel.eu> Signed-off-by: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
This commit is contained in:
parent
2e8c04f757
commit
b34050fadb
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
@ -293,6 +294,79 @@ static int charlcd_init_display(struct charlcd *lcd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses an unsigned integer from a string, until a non-digit character
|
||||
* is found. The empty string is not accepted. No overflow checks are done.
|
||||
*
|
||||
* Returns whether the parsing was successful. Only in that case
|
||||
* the output parameters are written to.
|
||||
*
|
||||
* TODO: If the kernel adds an inplace version of kstrtoul(), this function
|
||||
* could be easily replaced by that.
|
||||
*/
|
||||
static bool parse_n(const char *s, unsigned long *res, const char **next_s)
|
||||
{
|
||||
if (!isdigit(*s))
|
||||
return false;
|
||||
|
||||
*res = 0;
|
||||
while (isdigit(*s)) {
|
||||
*res = *res * 10 + (*s - '0');
|
||||
++s;
|
||||
}
|
||||
|
||||
*next_s = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses a movement command of the form "(.*);", where the group can be
|
||||
* any number of subcommands of the form "(x|y)[0-9]+".
|
||||
*
|
||||
* Returns whether the command is valid. The position arguments are
|
||||
* only written if the parsing was successful.
|
||||
*
|
||||
* For instance:
|
||||
* - ";" returns (<original x>, <original y>).
|
||||
* - "x1;" returns (1, <original y>).
|
||||
* - "y2x1;" returns (1, 2).
|
||||
* - "x12y34x56;" returns (56, 34).
|
||||
* - "" fails.
|
||||
* - "x" fails.
|
||||
* - "x;" fails.
|
||||
* - "x1" fails.
|
||||
* - "xy12;" fails.
|
||||
* - "x12yy12;" fails.
|
||||
* - "xx" fails.
|
||||
*/
|
||||
static bool parse_xy(const char *s, unsigned long *x, unsigned long *y)
|
||||
{
|
||||
unsigned long new_x = *x;
|
||||
unsigned long new_y = *y;
|
||||
|
||||
for (;;) {
|
||||
if (!*s)
|
||||
return false;
|
||||
|
||||
if (*s == ';')
|
||||
break;
|
||||
|
||||
if (*s == 'x') {
|
||||
if (!parse_n(s + 1, &new_x, &s))
|
||||
return false;
|
||||
} else if (*s == 'y') {
|
||||
if (!parse_n(s + 1, &new_y, &s))
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*x = new_x;
|
||||
*y = new_y;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* These are the file operation function for user access to /dev/lcd
|
||||
* This function can also be called from inside the kernel, by
|
||||
|
@ -471,24 +545,11 @@ static inline int handle_lcd_special_code(struct charlcd *lcd)
|
|||
}
|
||||
case 'x': /* gotoxy : LxXXX[yYYY]; */
|
||||
case 'y': /* gotoxy : LyYYY[xXXX]; */
|
||||
if (!strchr(esc, ';'))
|
||||
break;
|
||||
/* If the command is valid, move to the new address */
|
||||
if (parse_xy(esc, &priv->addr.x, &priv->addr.y))
|
||||
charlcd_gotoxy(lcd);
|
||||
|
||||
while (*esc) {
|
||||
if (*esc == 'x') {
|
||||
esc++;
|
||||
if (kstrtoul(esc, 10, &priv->addr.x) < 0)
|
||||
break;
|
||||
} else if (*esc == 'y') {
|
||||
esc++;
|
||||
if (kstrtoul(esc, 10, &priv->addr.y) < 0)
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
charlcd_gotoxy(lcd);
|
||||
/* Regardless of its validity, mark as processed */
|
||||
processed = 1;
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user