#include #include #include #include #include #include #include #include #include #include #include "util.h" static void _stdio_open_switch(ft_test *t) { int fd, rc; FILE *fp; /* Create a basic file */ DO_E(fd, creat("ft_stdio.txt", 0755), t, "%d"); ft_assert(t, fd >= 0); DO_E(rc, write(fd, "Hello, stdio!\n", 14), t, "%d"); ft_assert(t, rc == 14); DO_E(rc, close(fd), t, "%d"); ft_assert(t, rc == 0); /* Try to open it with */ DO_E(fp, fopen("ft_stdio.txt", "r"), t, "%p"); ft_assert(t, fp != NULL); ft_log_FILE(t, "", fp); if(!fp) return; /* Change buffer settings a couple times */ DO_E(rc, setvbuf(fp, NULL, _IONBF, 0), t, "%d"); ft_assert(t, rc == 0); ft_log_FILE(t, "", fp); DO_E(rc, setvbuf(fp, NULL, _IOLBF, 1024), t, "%d"); ft_assert(t, rc == 0); ft_log_FILE(t, "", fp); DO_E(rc, setvbuf(fp, NULL, _IOFBF, BUFSIZ), t, "%d"); ft_assert(t, rc == 0); ft_log_FILE(t, "", fp); /* Reopen with different permissions */ DO_E(fp, freopen("ft_stdio.txt", "w+", fp), t, "%p"); ft_assert(t, fp != NULL); ft_log_FILE(t, "", fp); DO_E(fp, freopen("ft_stdio.txt", "rb+", fp), t, "%p"); ft_assert(t, fp != NULL); ft_log_FILE(t, "", fp); DO_E(fp, freopen("ft_stdio.txt", "ab", fp), t, "%p"); ft_assert(t, fp != NULL); ft_log_FILE(t, "", fp); DO_E(fp, freopen("ft_stdio.txt", "w", fp), t, "%p"); ft_assert(t, fp != NULL); ft_log_FILE(t, "", fp); DO_E(rc, fclose(fp), t, "%d"); ft_assert(t, rc == 0); } static void _stdio_open(ft_test *t) { gint_world_switch(GINT_CALL(_stdio_open_switch, (void *)t)); } ft_test ft_stdio_open = { .name = "Opening files", .function = _stdio_open, }; static char const *filler = "The fread function reads, into the array pointed to by ptr, up to nmemb " "elements whose size is specified by size, from the stream pointed to by " "stream. For each object, size calls are made to the fgetc function and the " "results stored, in the order read, in an array of unsigned char exactly " "overlaying the object. The file position indicator for the stream (if " "defined) is advanced by the number of characters successfully read. If an " "error occurs, the resulting value of the file position indicator for the " "stream is indeterminate. If a partial element is read, its value is " "indeterminate.\n"; /* length 591 */ static void _ft_stdio_simple_read_switch(ft_test *t) { int fd, rc; FILE *fp; char *str = malloc(384); /* Create a basic large file (compared to its buffer size) */ DO_E(fd, creat("ft_stdio.txt", 0755), t, "%d"); ft_assert(t, fd >= 0); DO_E(rc, write(fd, filler, 591), t, "%d"); ft_assert(t, rc == 591); DO_E(rc, close(fd), t, "%d"); ft_assert(t, rc == 0); /* Read it through a buffer of size 128 */ DO_E(fp, fopen("ft_stdio.txt", "r"), t, "%p"); ft_assert(t, fp != NULL); ft_log_FILE(t, "", fp); DO_E(rc, setvbuf(fp, NULL, _IOFBF, 128), t, "%d"); ft_assert(t, rc == 0); ft_log_FILE(t, "", fp); DO_E(rc, ftell(fp), t, "%d"); ft_assert(t, rc == 0); /* Perform a first read of 16 bytes */ DO_E(rc, fread(str, 1, 16, fp), t, "%d"); ft_assert(t, rc == 16 && !memcmp(str, "The fread functi", 16)); ft_log_FILE(t, "", fp); ft_assert(t, fp->bufdir == __FILE_BUF_READ); ft_assert(t, fp->fdpos == 128); ft_assert(t, fp->bufread == 128); ft_assert(t, fp->bufpos == 16); ft_assert(t, fp->eof == 0); ft_assert(t, feof(fp) == 0); /* Perform several reads that are longer than the buffer */ DO_E(rc, fread(str, 1, 384, fp), t, "%d"); ft_assert(t, rc == 384 && !memcmp(str, filler+16, 384)); ft_log_FILE(t, "", fp); ft_assert(t, fp->bufdir == __FILE_BUF_READ); ft_assert(t, fp->fdpos == 512); ft_assert(t, fp->bufread == 128); ft_assert(t, fp->bufpos == 16); ft_assert(t, fp->eof == 0); ft_assert(t, feof(fp) == 0); /* Flush that buffer and check that we remain in place */ DO_E(rc, fflush(fp), t, "%d"); ft_assert(t, rc == 0); ft_log_FILE(t, "", fp); ft_assert(t, fp->bufdir == __FILE_BUF_READ); ft_assert(t, fp->fdpos == 400); ft_assert(t, fp->bufread == 0); ft_assert(t, fp->bufpos == 0); DO_E(rc, ftell(fp), t, "%d"); ft_assert(t, rc == 400); /* Do another standard read that will reach end-of-file on the fd */ DO_E(rc, fread(str, 1, 150, fp), t, "%d"); ft_assert(t, rc == 150); ft_log_FILE(t, "", fp); ft_assert(t, fp->bufdir == __FILE_BUF_READ); ft_assert(t, fp->fdpos == 591); ft_assert(t, fp->bufread == 63); ft_assert(t, fp->bufpos == 22); ft_assert(t, fp->eof == 1); ft_assert(t, feof(fp) == 0); /* Do one last read that will not be entirely fulfilled */ DO_E(rc, fread(str, 1, 64, fp), t, "%d"); ft_assert(t, rc == 41); ft_log_FILE(t, "", fp); ft_assert(t, fp->bufdir == __FILE_BUF_READ); ft_assert(t, fp->fdpos == 591); ft_assert(t, fp->bufread == 0); ft_assert(t, fp->bufpos == 0); ft_assert(t, fp->eof == 1); ft_assert(t, feof(fp) == 1); DO_E(rc, ftell(fp), t, "%d"); ft_assert(t, rc == 591); /* Rewind and move around */ rewind(fp); ft_log(t, "rewind(fp)\n"); DO_E(rc, ftell(fp), t, "%d"); ft_assert(t, rc == 0); DO_E(rc, fseek(fp, -20, SEEK_END), t, "%d"); ft_assert(t, rc == 0); DO_E(rc, ftell(fp), t, "%d"); ft_assert(t, rc == 571); ft_assert(t, fp->eof == 0); ft_assert(t, feof(fp) == 0); /* Seek at end of file, the EOF flag should be cleared */ DO_E(rc, fseek(fp, 0, SEEK_END), t, "%d"); ft_assert(t, rc == 0); DO_E(rc, ftell(fp), t, "%d"); ft_assert(t, rc == 591); ft_assert(t, fp->eof == 0); ft_assert(t, feof(fp) == 0); /* Attempt to read and get 0+EOF but no error */ DO_E(rc, fread(str, 8, 1, fp), t, "%d"); ft_assert(t, rc == 0); ft_assert(t, fp->eof == 1); ft_assert(t, feof(fp) == 1); /* Read into the buffer, then flush by seeking */ DO_E(rc, fseek(fp, 0, SEEK_SET), t, "%d"); ft_assert(t, rc == 0); DO_E(rc, fread(str, 1, 64, fp), t, "%d"); ft_assert(t, rc == 64); ft_assert(t, !memcmp(str, filler, 64)); ft_log_FILE(t, "", fp); ft_assert(t, fp->bufdir == __FILE_BUF_READ); ft_assert(t, fp->fdpos == 128); ft_assert(t, fp->bufread == 128); ft_assert(t, fp->bufpos == 64); ft_assert(t, fp->eof == 0); ft_assert(t, feof(fp) == 0); DO_E(rc, fseek(fp, 16, SEEK_SET), t, "%d"); ft_assert(t, rc == 0); ft_log_FILE(t, "", fp); ft_assert(t, fp->fdpos == 16); ft_assert(t, fp->bufread == 0); ft_assert(t, fp->bufpos == 0); ft_assert(t, fp->eof == 0); ft_assert(t, feof(fp) == 0); DO_E(rc, fread(str, 1, 64, fp), t, "%d"); ft_assert(t, rc == 64); ft_assert(t, !memcmp(str, filler+16, 64)); ft_log_FILE(t, "", fp); ft_assert(t, fp->bufdir == __FILE_BUF_READ); ft_assert(t, fp->fdpos == 144); ft_assert(t, fp->bufread == 128); ft_assert(t, fp->bufpos == 64); ft_assert(t, fp->eof == 0); ft_assert(t, feof(fp) == 0); DO_E(rc, fclose(fp), t, "%d"); ft_assert(t, rc == 0); free(str); } static void _ft_stdio_simple_read(ft_test *t) { gint_world_switch(GINT_CALL(_ft_stdio_simple_read_switch, (void *)t)); } ft_test ft_stdio_simple_read = { .name = "Simple file reading", .function = _ft_stdio_simple_read, };