ed

simple ed
git clone git://git.2f30.org/ed
Log | Files | Refs | LICENSE

commit 87c56d264c0f11c17339bf751e16a5d4020ecb71
parent 43caad39eb764d7de73bf651e97619afe339ceee
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Tue,  8 Dec 2015 21:21:29 +0100

Change getlst() to a getchar() parser alike function

We need this change, because the behaviour of readcmd()
depends on which part of the command we are, so it is
a very bad idea to read the full line at the beginning.
This commit is going to break a lot of things, for sure,
even when the last patch serie try to minimize it, but
it is a big change. Regular expression in address
were disabled, because they were also used in commands,
and since we didn't want to modify them, it was needed
this small inconvenience.

Diffstat:
Med.c | 101++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
1 file changed, 59 insertions(+), 42 deletions(-)

diff --git a/ed.c b/ed.c @@ -310,22 +310,41 @@ invalid: } static int +xgetnum(void) +{ + int ln, n, c; + + for (ln = 0; isdigit(c = getchar()); ln += n) { + if (ln > INT_MAX/10) + goto invalid; + n = c - '0'; + ln *= 10; + if (INT_MAX - ln < n) + goto invalid; + } + ungetc(c, stdin); + return ln; + +invalid: + error("invalid address"); +} + +static int linenum(int *line) { - int ln, c, sign = 1; + int ln, c, sign = 1, ret = 1; - while (isspace(*cmdp)) - ++cmdp; + while (isspace(c = getchar())) + /* nothing */; - switch (*cmdp) { + switch (c) { case '.': ln = curln; break; case '\'': - ++cmdp; - while (isspace(*cmdp)) - ++cmdp; - if (!isalpha(c = *cmdp)) + while (isspace(c = getchar())) + /* nothing */; + if (!isalpha(c)) error("invalid mark character"); if (!(ln = marks[c])) error("invalid address"); @@ -336,21 +355,24 @@ linenum(int *line) case '?': sign = -sign; case '/': - c = *cmdp; - compile(); - ln = match(c); + // compile(); + // ln = match(c); break; - default: - if (!isdigit(*cmdp)) - return 0; - *line = getnum(); case '-': case '+': - return 1; + ln = curln; + ungetc(c, stdin); + break; + default: + ungetc(c, stdin); + if (isdigit(c)) + ln = xgetnum(); + else + ret = 0; + break; } - ++cmdp; *line = ln; - return 1; + return ret; } static int @@ -358,62 +380,57 @@ address(int *line) { int ln, sign, c, num; - /* - * FIXME:we are getting the full line using - * a function that deals with escape - * character, and it means that it - * will remove the escape characters - * in the address, transforming - * /\// into ///, which will produce an - * error. - */ if (!linenum(&ln)) return 0; for (;;) { - while (isspace(*cmdp)) - ++cmdp; - c = *cmdp++; + while (isspace(c = getchar())) + /* nothing */; if (c != '+' && c != '-') break; sign = c == '+'; - if (!linenum(&num)) - num = 1; - /* FIXME: detect integer overflow here */ + num = isdigit(ungetc(getchar(), stdin)) ? xgetnum() : 1; + num *= sign; + if (INT_MAX - ln < num) + goto invalid; ln += sign * num; } - --cmdp; + ungetc(c, stdin); if (ln < 0 || ln > lastln) error("invalid address"); *line = ln; return 1; + +invalid: + error("invalid address"); } static void getlst() { - int ln; + int ln, c; - if (*cmdp == ',') { - ++cmdp; + if ((c = getchar()) == ',') { line1 = 1; line2 = lastln; nlines = lastln; return; } + ungetc(c, stdin); line2 = curln; for (nlines = 0; address(&ln); ) { line1 = line2; line2 = ln; ++nlines; - while (isspace(*cmdp)) - ++cmdp; - if (*cmdp != ',' && *cmdp != ';') + while (isspace(c = getchar())) + /* nothing */; + if (c != ',' && c != ';') break; - if (*cmdp++ == ';') + if (c == ';') curln = line2; } + ungetc(c, stdin); if (nlines > 2) nlines = 2; else if (nlines <= 1) @@ -1066,8 +1083,8 @@ main(int argc, char *argv[]) for (;;) { if (optprompt) fputs(prompt, stdout); - readcmd(); getlst(); + readcmd(); if (chkglobal()) doglobal(); else