|
11 | 11 | */
|
12 | 12 |
|
13 | 13 | #include <linux/atomic.h>
|
| 14 | +#include <linux/ctype.h> |
14 | 15 | #include <linux/delay.h>
|
15 | 16 | #include <linux/fs.h>
|
16 | 17 | #include <linux/miscdevice.h>
|
@@ -293,6 +294,79 @@ static int charlcd_init_display(struct charlcd *lcd)
|
293 | 294 | return 0;
|
294 | 295 | }
|
295 | 296 |
|
| 297 | +/* |
| 298 | + * Parses an unsigned integer from a string, until a non-digit character |
| 299 | + * is found. The empty string is not accepted. No overflow checks are done. |
| 300 | + * |
| 301 | + * Returns whether the parsing was successful. Only in that case |
| 302 | + * the output parameters are written to. |
| 303 | + * |
| 304 | + * TODO: If the kernel adds an inplace version of kstrtoul(), this function |
| 305 | + * could be easily replaced by that. |
| 306 | + */ |
| 307 | +static bool parse_n(const char *s, unsigned long *res, const char **next_s) |
| 308 | +{ |
| 309 | + if (!isdigit(*s)) |
| 310 | + return false; |
| 311 | + |
| 312 | + *res = 0; |
| 313 | + while (isdigit(*s)) { |
| 314 | + *res = *res * 10 + (*s - '0'); |
| 315 | + ++s; |
| 316 | + } |
| 317 | + |
| 318 | + *next_s = s; |
| 319 | + return true; |
| 320 | +} |
| 321 | + |
| 322 | +/* |
| 323 | + * Parses a movement command of the form "(.*);", where the group can be |
| 324 | + * any number of subcommands of the form "(x|y)[0-9]+". |
| 325 | + * |
| 326 | + * Returns whether the command is valid. The position arguments are |
| 327 | + * only written if the parsing was successful. |
| 328 | + * |
| 329 | + * For instance: |
| 330 | + * - ";" returns (<original x>, <original y>). |
| 331 | + * - "x1;" returns (1, <original y>). |
| 332 | + * - "y2x1;" returns (1, 2). |
| 333 | + * - "x12y34x56;" returns (56, 34). |
| 334 | + * - "" fails. |
| 335 | + * - "x" fails. |
| 336 | + * - "x;" fails. |
| 337 | + * - "x1" fails. |
| 338 | + * - "xy12;" fails. |
| 339 | + * - "x12yy12;" fails. |
| 340 | + * - "xx" fails. |
| 341 | + */ |
| 342 | +static bool parse_xy(const char *s, unsigned long *x, unsigned long *y) |
| 343 | +{ |
| 344 | + unsigned long new_x = *x; |
| 345 | + unsigned long new_y = *y; |
| 346 | + |
| 347 | + for (;;) { |
| 348 | + if (!*s) |
| 349 | + return false; |
| 350 | + |
| 351 | + if (*s == ';') |
| 352 | + break; |
| 353 | + |
| 354 | + if (*s == 'x') { |
| 355 | + if (!parse_n(s + 1, &new_x, &s)) |
| 356 | + return false; |
| 357 | + } else if (*s == 'y') { |
| 358 | + if (!parse_n(s + 1, &new_y, &s)) |
| 359 | + return false; |
| 360 | + } else { |
| 361 | + return false; |
| 362 | + } |
| 363 | + } |
| 364 | + |
| 365 | + *x = new_x; |
| 366 | + *y = new_y; |
| 367 | + return true; |
| 368 | +} |
| 369 | + |
296 | 370 | /*
|
297 | 371 | * These are the file operation function for user access to /dev/lcd
|
298 | 372 | * 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)
|
471 | 545 | }
|
472 | 546 | case 'x': /* gotoxy : LxXXX[yYYY]; */
|
473 | 547 | case 'y': /* gotoxy : LyYYY[xXXX]; */
|
474 |
| - if (!strchr(esc, ';')) |
475 |
| - break; |
476 |
| - |
477 |
| - while (*esc) { |
478 |
| - if (*esc == 'x') { |
479 |
| - esc++; |
480 |
| - if (kstrtoul(esc, 10, &priv->addr.x) < 0) |
481 |
| - break; |
482 |
| - } else if (*esc == 'y') { |
483 |
| - esc++; |
484 |
| - if (kstrtoul(esc, 10, &priv->addr.y) < 0) |
485 |
| - break; |
486 |
| - } else { |
487 |
| - break; |
488 |
| - } |
489 |
| - } |
| 548 | + /* If the command is valid, move to the new address */ |
| 549 | + if (parse_xy(esc, &priv->addr.x, &priv->addr.y)) |
| 550 | + charlcd_gotoxy(lcd); |
490 | 551 |
|
491 |
| - charlcd_gotoxy(lcd); |
| 552 | + /* Regardless of its validity, mark as processed */ |
492 | 553 | processed = 1;
|
493 | 554 | break;
|
494 | 555 | }
|
|
0 commit comments