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/atomic.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
@ -293,6 +294,79 @@ static int charlcd_init_display(struct charlcd *lcd)
|
|||||||
return 0;
|
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
|
* These are the file operation function for user access to /dev/lcd
|
||||||
* This function can also be called from inside the kernel, by
|
* 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 'x': /* gotoxy : LxXXX[yYYY]; */
|
||||||
case 'y': /* gotoxy : LyYYY[xXXX]; */
|
case 'y': /* gotoxy : LyYYY[xXXX]; */
|
||||||
if (!strchr(esc, ';'))
|
/* If the command is valid, move to the new address */
|
||||||
break;
|
if (parse_xy(esc, &priv->addr.x, &priv->addr.y))
|
||||||
|
charlcd_gotoxy(lcd);
|
||||||
|
|
||||||
while (*esc) {
|
/* Regardless of its validity, mark as processed */
|
||||||
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);
|
|
||||||
processed = 1;
|
processed = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user