Browse Source

Improved file.read method

Marco Bambini 4 years ago
parent
commit
503e7e855e
1 changed files with 53 additions and 7 deletions
  1. 53 7
      src/optionals/gravity_opt_file.c

+ 53 - 7
src/optionals/gravity_opt_file.c

@@ -280,21 +280,58 @@ static bool internal_file_iread (gravity_vm *vm, gravity_value_t *args, uint16_t
     // var data = file.read(N)
     
     // 1 parameter of type int is required
-    if (nargs < 1 && !VALUE_ISA_INT(args[1])) {
-        RETURN_ERROR("A path parameter of type Int is required.");
+    if (nargs < 1 && (!VALUE_ISA_INT(args[1]) && !VALUE_ISA_STRING(args[1]))) {
+        RETURN_ERROR("A parameter of type Int or String is required.");
     }
     
     gravity_file_t *instance = VALUE_AS_FILE(args[0]);
-    gravity_int_t n = VALUE_AS_INT(args[1]);
+    gravity_int_t n = 256;
+    gravity_string_t *str = NULL;
+    size_t nread = 0;
     
-    char *b = (char *)mem_alloc(NULL, n);
-    if (!b) {
+    if (VALUE_ISA_INT(args[1])) n = VALUE_AS_INT(args[1]);
+    else str = VALUE_AS_STRING(args[1]);
+    
+    char *buffer = (char *)mem_alloc(NULL, n);
+    if (!buffer) {
         RETURN_ERROR("Not enought memory to allocate required buffer.");
     }
     
-    size_t nread = fread(b, (size_t)n, 1, instance->file);
-    gravity_string_t *result = gravity_string_new(vm, b, (uint32_t)nread, (uint32_t)n);
+    // args[1] was a number so read up-to n characters
+    if (str == NULL) {
+        nread = fread(buffer, (size_t)n, 1, instance->file);
+    } else {
+        // read up-until s character was found (or EOF)
+        // taking in account buffer b resizing
+        // algorithm modified from: http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/pkgsrc/pkgtools/libnbcompat/files/getdelim.c
+        
+        int delimiter = (int)str->s[0];
+        char *ptr, *eptr;
+        
+        for (ptr = buffer, eptr = buffer + n; ++nread;) {
+            int c = fgetc(instance->file);
+            if ((c == -1) || feof(instance->file)) break;
+            
+            *ptr++ = c;
+            if (c == delimiter) break;
+            
+            if (ptr + 2 >= eptr) {
+                char *nbuf;
+                size_t nbufsiz = n * 2;
+                ssize_t d = ptr - buffer;
+                if ((nbuf = mem_realloc(NULL, buffer, nbufsiz)) == NULL) break;
+                
+                buffer = nbuf;
+                n = nbufsiz;
+                eptr = nbuf + nbufsiz;
+                ptr = nbuf + d;
+            }
+        }
+        // NULL terminate the string
+        buffer[nread] = 0;
+    }
     
+    gravity_string_t *result = gravity_string_new(vm, buffer, (uint32_t)nread, (uint32_t)n);
     RETURN_VALUE(VALUE_FROM_OBJECT(result), rindex);
 }
 
@@ -347,6 +384,14 @@ static bool internal_file_iflush (gravity_vm *vm, gravity_value_t *args, uint16_
     RETURN_VALUE(VALUE_FROM_INT(result), rindex);
 }
 
+static bool internal_file_iisEOF (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+    // var isEOF = file.isEOF()
+    UNUSED_PARAM(nargs);
+    gravity_file_t *instance = VALUE_AS_FILE(args[0]);
+    int result = feof(instance->file);
+    RETURN_VALUE(VALUE_FROM_BOOL(result != 0), rindex);
+}
+
 static bool internal_file_iclose (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
     UNUSED_PARAM(nargs);
     
@@ -386,6 +431,7 @@ static void create_optional_class (void) {
     gravity_class_bind(gravity_class_file, "read", NEW_CLOSURE_VALUE(internal_file_iread));
     gravity_class_bind(gravity_class_file, "write", NEW_CLOSURE_VALUE(internal_file_iwrite));
     gravity_class_bind(gravity_class_file, "seek", NEW_CLOSURE_VALUE(internal_file_iseek));
+    gravity_class_bind(gravity_class_file, "isEOF", NEW_CLOSURE_VALUE(internal_file_iisEOF));
     gravity_class_bind(gravity_class_file, "error", NEW_CLOSURE_VALUE(internal_file_ierror));
     gravity_class_bind(gravity_class_file, "flush", NEW_CLOSURE_VALUE(internal_file_iflush));
     gravity_class_bind(gravity_class_file, "close", NEW_CLOSURE_VALUE(internal_file_iclose));