*/
#include <linux/atomic.h>
+#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
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
}
case 'x': /* gotoxy : LxXXX[yYYY]; */
case 'y': /* gotoxy : LyYYY[xXXX]; */
- if (!strchr(esc, ';'))
- break;
-
- 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;
- }
- }
+ /* If the command is valid, move to the new address */
+ if (parse_xy(esc, &priv->addr.x, &priv->addr.y))
+ charlcd_gotoxy(lcd);
- charlcd_gotoxy(lcd);
+ /* Regardless of its validity, mark as processed */
processed = 1;
break;
}