Browse Source

re-implementation of functions "write" and "read"

Roberto Ierusalimschy 30 years ago
parent
commit
f57afd6e32
1 changed files with 256 additions and 253 deletions
  1. 256 253
      iolib.c

+ 256 - 253
iolib.c

@@ -3,7 +3,7 @@
 ** Input/output library to LUA
 */
 
-char *rcs_iolib="$Id: iolib.c,v 1.26 1995/10/26 14:21:56 roberto Exp roberto $";
+char *rcs_iolib="$Id: iolib.c,v 1.27 1995/11/03 15:43:50 roberto Exp roberto $";
 
 #include <stdio.h>
 #include <ctype.h>
@@ -20,26 +20,14 @@ char *rcs_iolib="$Id: iolib.c,v 1.26 1995/10/26 14:21:56 roberto Exp roberto $";
 static FILE *in=stdin, *out=stdout;
 
 
-#ifndef POPEN
+#ifdef POPEN
+FILE *popen();
+int pclose();
+#else
 #define popen(x,y) NULL  /* that is, popen always fails */
 #define pclose(x)  (-1)
 #endif
 
-static void str_error(char *funcname)
-{
-  char buff[250];
-  sprintf(buff, "incorrect arguments to function `%s'", funcname);
-  lua_error(buff);
-}
-
-static char *check_and_get_string (int numArg, char *funcname)
-{
-  lua_Object o = lua_getparam(numArg);
-  if (!(lua_isstring(o) || lua_isnumber(o)))
-    str_error(funcname);
-  return lua_getstring(o);
-}
-
 
 static void closeread (void)
 {
@@ -67,7 +55,7 @@ static void closewrite (void)
 **			status = readfrom (filename)
 ** where:
 **			status = 1 -> success
-**			status = 0 -> error
+**			status = nil -> error
 */
 static void io_readfrom (void)
 {
@@ -78,10 +66,10 @@ static void io_readfrom (void)
  }
  else
  {
-   char *s = check_and_get_string(1, "readfrom");
+   char *s = lua_check_string(1, "readfrom");
    FILE *fp = (*s == '|') ? popen(s+1, "r") : fopen(s, "r");
    if (fp == NULL)
-    lua_pushnumber (0);
+    lua_pushnil();
    else
    {
     closeread();
@@ -98,7 +86,7 @@ static void io_readfrom (void)
 **			status = writeto (filename)
 ** where:
 **			status = 1 -> success
-**			status = 0 -> error
+**			status = nil -> error
 */
 static void io_writeto (void)
 {
@@ -109,10 +97,10 @@ static void io_writeto (void)
  }
  else
  {
-   char *s = check_and_get_string(1, "writeto");
+   char *s = lua_check_string(1, "writeto");
    FILE *fp = (*s == '|') ? popen(s+1,"w") : fopen(s,"w");
    if (fp == NULL)
-    lua_pushnumber (0);
+    lua_pushnil();
    else
    {
     closewrite();
@@ -130,16 +118,16 @@ static void io_writeto (void)
 ** where:
 **			status = 2 -> success (already exist)
 **			status = 1 -> success (new file)
-**			status = 0 -> error
+**			status = nil -> error
 */
 static void io_appendto (void)
 {
- char *s = check_and_get_string(1, "appendto");
+ char *s = lua_check_string(1, "appendto");
  struct stat st;
  int r = (stat(s, &st) == -1) ? 1 : 2;
  FILE *fp = fopen (s, "a");
  if (fp == NULL)
-  lua_pushnumber (0);
+  lua_pushnil();
  else
  {
   if (out != stdout) fclose (out);
@@ -149,6 +137,72 @@ static void io_appendto (void)
 }
 
 
+static char getformat (char *f, int *just, int *m, int *n)
+{
+  int t;
+  switch (*f++)
+  {
+    case 's': case 'S':
+      t = 's';
+      break;
+    case 'f': case 'F': case 'g': case 'G': case 'e': case 'E':
+      t = 'f';
+      break;
+    case 'i': case 'I':
+      t = 'i';
+      break;
+    default:
+      t = 0;  /* to avoid compiler warnings */
+      lua_arg_error("read/write (format)");
+  }
+  *just = (*f == '<' || *f == '>' || *f == '|') ? *f++ : '>';
+  if (isdigit(*f))
+  {
+    *m = 0;
+    while (isdigit(*f))
+      *m = *m*10 + (*f++ - '0');
+  }
+  else
+    *m = -1;
+  if (*f == '.')
+  {
+    f++;	/* skip point */
+    *n = 0;
+    while (isdigit(*f))
+      *n = *n*10 + (*f++ - '0');
+  }
+  else
+    *n = -1;
+  return t;
+}
+
+
+static char *add_char (int c)
+{
+  static char *buff = NULL;
+  static int max = 0;
+  static int n = 0;
+  if (n >= max)
+  {
+    if (max == 0)
+    {
+      max = 100;
+      buff = (char *)malloc(max);
+    }
+    else
+    {
+      max *= 2;
+      buff = (char *)realloc(buff, max);
+    }
+    if (buff == NULL)
+      lua_error("memory overflow");
+  }
+  buff[n++] = c;
+  if (c == 0)
+    n = 0;  /* prepare for next string */
+  return buff;
+}
+
 /*
 ** Read a variable. On error put nil on stack.
 ** LUA interface:
@@ -163,125 +217,100 @@ static void io_appendto (void)
 **	Estes especificadores podem vir seguidos de numero que representa
 **	o numero de campos a serem lidos.
 */
-static void io_read (void)
+
+static int read_until_char (int del)
+{
+  int c;
+  while((c = fgetc(in)) != EOF && c != del)
+    add_char(c);
+  return c;
+}
+
+static int read_until_blank (void)
+{
+  int c;
+  while((c = fgetc(in)) != EOF && !isspace(c))
+    add_char(c);
+  return c;
+}
+
+static void read_m (int m)
+{
+  int c;
+  while (m-- && (c = fgetc(in)) != EOF)
+    add_char(c);
+}
+
+
+static void read_free (void)
 {
- lua_Object o = lua_getparam (1);
- if (o == LUA_NOOBJECT) 	/* free format */
- {
   int c;
-  char s[256];
   while (isspace(c=fgetc(in)))
    ;
   if (c == '\"' || c == '\'')
-  {
-   int del = c;
-   int n=0;
-   while((c = fgetc(in)) != del)
-   {
+  { /* string */
+    c = read_until_char(c);
     if (c == EOF)
     {
-     lua_pushnil ();
-     return;
+      add_char(0);  /* to be ready for next time */
+      lua_pushnil();
     }
-    s[n++] = c;
-   }
-   s[n] = 0;
+    else
+      lua_pushstring(add_char(0));
   }
   else
   {
-   double d;
-   ungetc (c, in);
-   if (fscanf (in, "%s", s) != 1)
-   {
-    lua_pushnil ();
-    return;
-   }
-   if (sscanf(s, "%lf %*c", &d) == 1)
-   {
-    lua_pushnumber (d);
-    return;
-   }
+    double d;
+    char dummy;
+    char *s;
+    add_char(c);
+    read_until_blank();
+    s = add_char(0);
+    if (sscanf(s, "%lf %c", &d, &dummy) == 1)
+      lua_pushnumber(d);
+    else
+     lua_pushstring(s);
   }
-  lua_pushstring (s);
-  return;
- }
- else				/* formatted */
- {
-  char *e = check_and_get_string(1, "read");
-  char t;
-  int  m=0;
-  while (isspace(*e)) e++;
-  t = *e++;
-  while (isdigit(*e))
-   m = m*10 + (*e++ - '0');
-  
-  if (m > 0)
-  {
-   char f[80];
-   char s[256];
-   sprintf (f, "%%%ds", m);
-   if (fgets (s, m+1, in) == NULL)
-   {
-    lua_pushnil();
-    return;
-   }
-   else
-   {
-    if (s[strlen(s)-1] == '\n')
-     s[strlen(s)-1] = 0;
-   }
-   switch (tolower(t))
-   {
-    case 'i':
-    {
-     long int l;
-     sscanf (s, "%ld", &l);
-     lua_pushnumber(l);
-    }
-    break;
-    case 'f': case 'g': case 'e':
-    {
-     float fl;
-     sscanf (s, "%f", &fl);
-     lua_pushnumber(fl);
-    }
-    break;
-    default: 
-     lua_pushstring(s); 
-    break;
-   }
-  }
-  else
+}
+
+static void io_read (void)
+{
+  lua_Object o = lua_getparam (1);
+  if (o == LUA_NOOBJECT) 	/* free format */
+    read_free();
+  else				/* formatted */
   {
-   switch (tolower(t))
-   {
-    case 'i':
-    {
-     long int l;
-     if (fscanf (in, "%ld", &l) == EOF)
-       lua_pushnil();
-       else lua_pushnumber(l);
-    }
-    break;
-    case 'f': case 'g': case 'e':
+    int m, dummy1, dummy2;
+    switch (getformat(lua_check_string(1, "read"), &dummy1, &m, &dummy2))
     {
-     float f;
-     if (fscanf (in, "%f", &f) == EOF)
-       lua_pushnil();
-       else lua_pushnumber(f);
-    }
-    break;
-    default: 
-    {
-     char s[256];
-     if (fscanf (in, "%s", s) == EOF)
-       lua_pushnil();
-       else lua_pushstring(s);
+      case 's':
+        if (m < 0)
+          read_until_blank();
+        else
+          read_m(m);
+        lua_pushstring(add_char(0));
+        break;
+
+      case 'i':  /* can read as float, since it makes no difference to Lua */
+      case 'f':
+      {
+        double d;
+        int result;
+        if (m < 0)
+          result = fscanf(in, "%lf", &d);
+        else
+        {
+          read_m(m);
+          result = sscanf(add_char(0), "%lf", &d);
+        }
+        if (result == 1)
+          lua_pushnumber(d);
+        else
+          lua_pushnil();
+        break;
+      }
     }
-    break;
-   }
   }
- }
 }
 
 
@@ -290,33 +319,13 @@ static void io_read (void)
 */
 static void io_readuntil (void)
 {
- int n=255,m=0;
- int c,d;
- char *s;
- lua_Object lo = lua_getparam(1);
- if (!lua_isstring(lo))
-  d = EOF; 
- else
-  d = *lua_getstring(lo);
- 
- s = (char *)malloc(n+1);
- while((c = fgetc(in)) != EOF && c != d)
- {
-  if (m==n)
-  {
-   n *= 2;
-   s = (char *)realloc(s, n+1);
-  }
-  s[m++] = c;
- }
+ int del = *lua_check_string(1, "readuntil");
+ int c = read_until_char(del);
  if (c != EOF) ungetc(c,in);
- s[m] = 0;
- lua_pushstring(s);
- free(s);
+ lua_pushstring(add_char(0));
 }
 
 
-
 /*
 ** Write a variable. On error put 0 on stack, otherwise put 1.
 ** LUA interface:
@@ -343,106 +352,100 @@ static void io_readuntil (void)
 **			inteiros -> numero minimo de digitos
 **			string -> nao se aplica
 */
-static char *buildformat (char *e, lua_Object o)
+
+static int write_fill (int n, int c)
 {
- static char buffer[2048];
- static char f[80];
- char *string = &buffer[255];
- char *fstart=e, *fspace, *send;
- char t, j='r';
- int  m=0, n=-1, l;
- while (isspace(*e)) e++;
- fspace = e;
- t = *e++;
- if (*e == '<' || *e == '|' || *e == '>') j = *e++;
- while (isdigit(*e))
-  m = m*10 + (*e++ - '0');
- if (*e == '.') e++;	/* skip point */
- while (isdigit(*e))
-  if (n < 0) n = (*e++ - '0');
-  else       n = n*10 + (*e++ - '0');
-
- sprintf(f,"%%");
- if (j == '<' || j == '|') sprintf(strchr(f,0),"-");
- if (m >  0)   sprintf(strchr(f,0),"%d", m);
- if (n >= 0)   sprintf(strchr(f,0),".%d", n);
- switch (t)
- {
-  case 'i': case 'I': t = 'd';
-   sprintf(strchr(f,0), "%c", t);
-   sprintf (string, f, (long int)lua_getnumber(o));
-  break;
-  case 'f': case 'g': case 'e': case 'G': case 'E': 
-   sprintf(strchr(f,0), "%c", t);
-   sprintf (string, f, (float)lua_getnumber(o));
-  break;
-  case 'F': t = 'f';
-   sprintf(strchr(f,0), "%c", t);
-   sprintf (string, f, (float)lua_getnumber(o));
-  break;
-  case 's': case 'S': t = 's';
-   sprintf(strchr(f,0), "%c", t);
-   sprintf (string, f, lua_getstring(o));
-  break;
-  default: return "";
- }
- l = strlen(string);
- send = string+l;
- if (m!=0 && l>m)
- {
-  int i;
-  for (i=0; i<m; i++)
-   string[i] = '*';
-  string[i] = 0;
- }
- else if (m!=0 && j=='|')
- {
-  int k;
-  int i=l-1;
-  while (isspace(string[i]) || string[i]==0) i--;
-  string -= (m-i)/2;
-  for(k=0; k<(m-i)/2; k++)
-   string[k] = ' ';
- }
- /* add space characteres */
- while (fspace != fstart)
- {
-  string--;
-  fspace--;
-  *string = *fspace; 
- }
- while (isspace(*e)) *send++ = *e++;
- *send = 0;
- return string;
+  while (n--)
+    if (fputc(c, out) == EOF)
+      return 0;
+  return 1;
 }
+
+static int write_string (char *s, int just, int m)
+{
+  int status;
+  int l = strlen(s);
+  int pre;  /* number of blanks before string */
+  if (m < 0) m = l;
+  else if (l > m)
+  {
+    write_fill(m, '*');
+    return 0;
+  }
+  pre = (just == '<') ? 0 : (just == '>') ? m-l : (m-l)/2;
+  status = write_fill(pre, ' ');
+  status = status && fprintf(out, "%s", s) >= 0;
+  status = status && write_fill(m-(l+pre), ' ');
+  return status;
+}
+
+static int write_float (int just, int m, int n)
+{
+  char buffer[100];
+  lua_Object p = lua_getparam(1);
+  float number;
+  if (!lua_isnumber(p)) return 0;
+  number = lua_getnumber(p);
+  if (n >= 0)
+    sprintf(buffer, "%.*f", n, number);
+  else
+    sprintf(buffer, "%g", number);
+  return write_string(buffer, just, m);
+}
+
+
+static int write_int (int just, int m, int n)
+{
+  char buffer[100];
+  lua_Object p = lua_getparam(1);
+  int number;
+  if (!lua_isnumber(p)) return 0;
+  number = (int)lua_getnumber(p);
+  if (n >= 0)
+    sprintf(buffer, "%.*d", n, number);
+  else
+    sprintf(buffer, "%d", number);
+  return write_string(buffer, just, m);
+}
+
+
 static void io_write (void)
 {
- lua_Object o1 = lua_getparam (1);
- lua_Object o2 = lua_getparam (2);
- if (o1 == LUA_NOOBJECT)			/* new line */
- {
-  fprintf (out, "\n");
-  lua_pushnumber(1);
- }
- else if (o2 == LUA_NOOBJECT)   		/* free format */
- {
-  int status=0;
-  if (lua_isnumber(o1))
-   status = fprintf (out, "%g", lua_getnumber(o1));
-  else if (lua_isstring(o1))
-   status = fprintf (out, "%s", lua_getstring(o1));
-  lua_pushnumber(status);
- }
- else					/* formated */
- {
-  if (!lua_isstring(o2))
-  { 
-   lua_error ("incorrect format to function `write'"); 
-   lua_pushnumber(0);
-   return;
+  int status = 0;
+  if (lua_getparam (2) == LUA_NOOBJECT)   /* free format */
+  {
+    lua_Object o1 = lua_getparam(1);
+    if (lua_isnumber(o1))
+      status = fprintf (out, "%g", lua_getnumber(o1)) >= 0;
+    else if (lua_isstring(o1))
+      status = fprintf (out, "%s", lua_getstring(o1)) >= 0;
   }
-  lua_pushnumber(fprintf (out, "%s", buildformat(lua_getstring(o2),o1)));
- }
+  else					/* formated */
+  {
+    int just, m, n;
+    switch (getformat (lua_check_string(2, "write"), &just, &m, &n))
+    {
+      case 's':
+      {
+        lua_Object p = lua_getparam(1);
+        if (lua_isstring(p))
+          status = write_string(lua_getstring(p), just, m);
+        else
+          status = 0;
+        break;
+      }
+      case 'f':
+        status = write_float(just, m, n);
+        break;
+      case 'i':
+        status = write_int(just, m, n);
+        break;
+    }
+  }
+  if (status)
+    lua_pushnumber(status);
+  else
+    lua_pushnil();
 }
 
 /*
@@ -451,19 +454,18 @@ static void io_write (void)
 */
 static void io_execute (void)
 {
-  lua_pushnumber(system(check_and_get_string(1, "execute")));
+  lua_pushnumber(system(lua_check_string(1, "execute")));
 }
 
 /*
-** Remove a file.
-** On error put 0 on stack, otherwise put 1.
+** Remove a file. On error return nil.
 */
 static void io_remove  (void)
 {
- if (remove(check_and_get_string(1, "remove")) == 0)
+ if (remove(lua_check_string(1, "remove")) == 0)
    lua_pushnumber (1);
  else
-   lua_pushnumber (0);
+   lua_pushnil();
 }
 
 
@@ -472,7 +474,7 @@ static void io_remove  (void)
 */
 static void io_getenv (void)
 {
- char *env = getenv(check_and_get_string(1, "getenv"));
+ char *env = getenv(lua_check_string(1, "getenv"));
  if (env == NULL) lua_pushnil();
  else             lua_pushstring(env); 
 }
@@ -612,3 +614,4 @@ void iolib_open (void)
  lua_register ("print_stack", errorfb);
  lua_setfallback("error", errorfb);
 }
+