() = evalfile ("inc.sl"); testing_feature ("stdio routines"); define fdopen_tmp_file (fileptr, mode, fdp) { variable file, fp, fd; @fileptr = NULL; file = util_make_tmp_file ("tmpfile", &fd); fp = fdopen (fd, mode); if (fp == NULL) failed ("fdopen failed: %s", errno_string()); @fdp = fd; @fileptr = file; return fp; } define fopen_tmp_file (fileptr, mode) { variable file, fp; @fileptr = NULL; file = util_make_tmp_file ("tmpfile", NULL); fp = fopen (file, mode); if (fp == NULL) failed ("Unable to open %S", file); @fileptr = file; return fp; } define run_tests (some_text, read_fun, write_fun, length_fun) { variable file, fp, fd; variable new_text, nbytes, len; variable pos; fp = fdopen_tmp_file (&file, "wb", &fd); #ifexists setvbuf if (-1 == setvbuf (fp, _IOFBF, 8)) failed ("setvbuf"); #endif if (-1 == @write_fun (some_text, fp)) failed (string (write_fun)); if (-1 == fclose (fp)) failed ("fclose"); fp = fopen (file, "rb"); if (fp == NULL) failed ("fopen existing"); len = @length_fun (some_text); nbytes = @read_fun (&new_text, len, fp); if ((nbytes != len) or (some_text != new_text)) failed (string (read_fun)); if (-1 != @read_fun (&new_text, 1, fp)) failed (string (read_fun) + " at EOF"); if (0 == feof (fp)) failed ("feof"); if (ferror (fp)) failed ("expected ferror to return 0"); clearerr (fp); if (feof (fp)) failed ("clearerr"); if (0 != fseek (fp, 0, SEEK_SET)) failed ("fseek"); nbytes = @read_fun (&new_text, len, fp); if ((nbytes != len) or (some_text != new_text)) failed (string (read_fun) + " after fseek"); pos = ftell (fp); if (pos == -1) failed ("ftell at EOF"); if (0 != fseek (fp, 0, SEEK_SET)) failed ("fseek"); if (0 != ftell (fp)) failed ("ftell at BOF"); if (0 != fseek (fp, pos, SEEK_CUR)) failed ("fseek to pos"); if (pos != ftell (fp)) failed ("ftell after fseek to pos"); if (feof (fp) != 0) failed ("feof after fseek to EOF"); () = fseek (fp, 0, SEEK_SET); nbytes = fread (&new_text, Char_Type, 0, fp); if (nbytes != 0) failed ("fread for 0 bytes"); nbytes = fread (&new_text, Char_Type, len + 100, fp); if (nbytes != len) failed ("fread for 100 extra bytes"); if (-1 == fclose (fp)) failed ("fclose after tests"); fd = open (file, O_RDONLY); if (fd == NULL) failed ("open %s failed", file); variable ofs = (@length_fun)(some_text) - 1; variable ofs1 = lseek (fd, ofs, SEEK_SET); if (ofs != ofs1) failed ("lseek returned %S, expected %S: %S", ofs1, ofs, errno_string()); if (1 != read (fd, &new_text, 1)) failed ("read failed after lseek"); if (new_text[0] != some_text[-1]) failed ("read failed to read the correct byte after lseek: 0x%X vs 0x%X", new_text[0], some_text[-1]); () = close (fd); () = remove (file); if (stat_file (file) != NULL) failed ("remove"); } static define do_fgets (addr, nbytes, fp) { variable count; variable dbytes, bytes; variable dc = fgets (&bytes, fp); if (dc == -1) return -1; count = dc; while (count < nbytes) { dc = fgets (&dbytes, fp); if (dc == -1) break; count += dc; bytes += dbytes; } @addr = bytes; return count; } static define do_fread (addr, nbytes, fp) { % return fread (addr, UChar_Type, nbytes, fp); return fread_bytes (addr, nbytes, fp); } private define do_fprintf (some_text, fp) { if (fprintf (fp, "%s", some_text) != strbytelen(some_text)) return -1; return 0; } private define do_foreach_char (addr, nbytes, fp) { variable ch, str = NULL, count = 0; foreach ch (fp) using ("char") { if (str == NULL) str = ""; str = strcat (str, char(-1*ch)); count++; if (count >= nbytes) break; } if (str == NULL) return -1; @addr = str; return count; } private define do_foreach_line (addr, nbytes, fp) { variable line, str = NULL, count = 0; foreach line (fp) using ("line") { if (str == NULL) str = ""; str = strcat (str, line); count += strbytelen(line); if (count >= nbytes) break; } if (str == NULL) return -1; @addr = str; return count; } run_tests ("ABCDEFG", &do_fgets, &fputs, &strlen); run_tests ("A\000BC\000\n\n\n", &do_fread, &fwrite, &bstrlen); run_tests ("A\nAB\n\ABC\nABCD", &do_fgets, &do_fprintf, &strbytelen); run_tests ("A\nAB\n\ABC\nABCD", &do_foreach_char, &fwrite, &strbytelen); run_tests ("A\nAB\n\ABC\nABCD", &do_foreach_line, &fwrite, &strbytelen); define test_fread_fwrite (x) { variable fp, file, str, n, m, y, type, ch; fp = fopen_tmp_file (&file, "w+b"); type = _typeof(x); n = length (x); if ((type == String_Type) or (type == BString_Type)) { %type = UChar_Type; n = bstrlen (x); } if (n != fwrite (x, fp)) failed ("test_fread_fwrite: fwrite"); if (-1 == fseek (fp, 0, SEEK_SET)) failed ("test_fread_fwrite: fseek"); if (n != fread (&y, type, n, fp)) failed ("test_fread_fwrite: fread"); if (length (where (y != x))) failed ("test_fread_fwrite: fread failed to return: " + string(x)); if (-1 == fseek (fp, 0, SEEK_SET)) failed ("test_fread_fwrite: fseek"); if (type == UChar_Type) { y = 0; foreach (fp) using ("char") { ch = (); if (ch != x[y]) failed ("foreach using char: %S != %S", ch, x[y]); y++; } if (y != n) failed ("foreach using char 2"); } () = fclose (fp); if (-1 == remove (file)) failed ("remove:" + errno_string(errno)); if (stat_file (file) != NULL) failed ("remove"); } test_fread_fwrite (""); test_fread_fwrite ("hello"); test_fread_fwrite ("hel\0\0lo"); test_fread_fwrite (Integer_Type[0]); test_fread_fwrite ([1:10]); #ifexists Double_Type test_fread_fwrite (3.17); test_fread_fwrite ([1:10:0.1]); #endif #ifexists Complex_Type test_fread_fwrite (Complex_Type[50] + 3 + 2i); test_fread_fwrite (2i+3); test_fread_fwrite ([2i+3, 7i+1]); #endif static define test_fgetsputslines () { variable lines, lines1; lines = array_map (String_Type, &string, [1:1000]); lines += "\n"; variable fp, file; fp = fopen_tmp_file (&file, "w"); if (length (lines) != fputslines (lines, fp)) failed ("fputslines"); if (-1 == fclose (fp)) failed ("fputslines;fclose"); fp = fopen (file, "r"); if (fp == NULL) failed ("fputslines...fopen"); lines1 = fgetslines (fp); if (0 == _eqs (lines1, lines)) failed ("fgetslines"); ()=fclose (fp); if (-1 == remove (file)) failed ("remove:" + errno_string(errno)); lines = array_map (String_Type, &string, [1:1000]); lines[[10:20:3]] = ""; lines = " \t" + lines + " \n"; variable a = Array_Type[4]; a[0] = lines; a[1] = strtrim_end (lines); a[2] = strtrim_beg (lines); a[3] = strtrim (lines); fp = fopen_tmp_file (&file, "w"); if (length (lines) != fputslines (lines, fp)) failed ("fputslines"); if (-1 == fclose (fp)) failed ("fputslines;fclose"); _for (0, 3, 1) { variable t = (); fp = fopen (file, "r"); if (fp == NULL) failed ("fputslines...fopen"); ifnot (_eqs (a[t], fgetslines (fp; trim=t))) failed ("fgetslines with trim=%d", t); () = fclose (fp); } if (-1 == remove (file)) failed ("remove:" + errno_string(errno)); } test_fgetsputslines (); define test_read_write () { variable file; variable fp = fopen_tmp_file (&file, "w"); variable fd = fileno (fp); variable str = "helloworld"; variable n = write (fd, str); if (n != strlen (str)) failed ("write(%s) returned %d", str, n); () = fclose (fp); fd = open (file, O_RDONLY); variable buf; n = read (fd, &buf, n); if (n != strlen (str)) failed ("read returned %d bytes", n); if (buf != str) failed ("read returned %s not %s", buf, str); () = close (fd); () = remove (file); } test_read_write(); #ifdef UNIX private define test_write_to_stdout () { () = fflush(stdout); variable fd = fileno (stdout); variable ifd = _fileno(stdout); variable old_stdout = dup_fd(fd); if (old_stdout == NULL) failed ("test_write_to_stdout: dup: %S", errno_string()); variable new_fd = open("/dev/null", O_WRONLY); if (-1 == dup2_fd(new_fd, ifd)) failed ("test_write_to_stdout: dup2: %S", errno_string()); () = close (new_fd); () = printf ("Write to stdout, fileno=%S", fileno(stdout)); () = fflush(stdout); () = dup2_fd(old_stdout, ifd); () = close (old_stdout); } test_write_to_stdout (); #endif #ifdef UNIX private define test_popen () { variable fp = popen ("ls", "r"); if (fp == NULL) failed ("popen ls failed"); variable count = 0; foreach (fp) using ("wsline") { variable line = (); count++; } if (0 != pclose (fp)) failed ("pclose: %S", errno_string()); if (count == 0) failed ("no lines read from popen ls"); } test_popen (); #endif private define test_bad_fds () { variable file; variable fp = fopen_tmp_file (&file, "w"); () = remove (file); if (NULL != fgetslines (fp, 0)) { () = fclose (fp); failed ("fgetslines on write-only stdio file pointer"); } clearerr (fp); if (-1 == fclose (fp)) failed ("fclose failed"); if (-1 != fclose (fp)) failed ("Expected second fclose to fail"); } test_bad_fds (); print ("Ok\n"); exit (0);