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:
M | ed.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