1 // RUN: %clangxx -g %s -o %t && %run %t | FileCheck %s 2 3 // CHECK: READ CALLED; len={{[0-9]*}} 4 // CHECK-NEXT: READ: test 5 // CHECK-NEXT: WRITE CALLED: test 6 // CHECK-NEXT: READ CALLED; len={{[0-9]*}} 7 // CHECK-NEXT: READ: test 8 // CHECK-NEXT: WRITE CALLED: test 9 // CHECK-NEXT: CLOSE CALLED 10 // CHECK-NEXT: SEEK CALLED; off=100, whence=0 11 // CHECK-NEXT: READ CALLED; len={{[0-9]*}} 12 // CHECK-NEXT: READ: test 13 // CHECK-NEXT: WRITE CALLED: test 14 // CHECK-NEXT: FLUSH CALLED 15 // CHECK-NEXT: WRITE CALLED: test 16 // CHECK-NEXT: FLUSH CALLED 17 18 #include <assert.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 int cookie_var; 24 25 ssize_t f_read(void *cookie, void *buf, size_t len) { 26 assert(cookie == &cookie_var); 27 assert(len >= 6); 28 printf("READ CALLED; len=%zd\n", len); 29 return strlcpy((char*)buf, "test\n", len); 30 } 31 32 ssize_t f_write(void *cookie, const void *buf, size_t len) { 33 assert(cookie == &cookie_var); 34 char *data = strndup((char*)buf, len); 35 assert(data); 36 printf("WRITE CALLED: %s\n", data); 37 free(data); 38 return len; 39 } 40 41 off_t f_seek(void *cookie, off_t off, int whence) { 42 assert(cookie == &cookie_var); 43 assert(whence == SEEK_SET); 44 printf("SEEK CALLED; off=%d, whence=%d\n", (int)off, whence); 45 return off; 46 } 47 48 int f_flush(void *cookie) { 49 assert(cookie == &cookie_var); 50 printf("FLUSH CALLED\n"); 51 return 0; 52 } 53 54 int f_close(void *cookie) { 55 assert(cookie == &cookie_var); 56 printf("CLOSE CALLED\n"); 57 return 0; 58 } 59 60 int main(void) { 61 FILE *fp; 62 char buf[10]; 63 64 // 1. read-only variant 65 fp = fropen2(&cookie_var, f_read); 66 assert(fp); 67 // verify that fileno() does not crash or report nonsense 68 assert(fileno(fp) == -1); 69 assert(fgets(buf, sizeof(buf), fp)); 70 printf("READ: %s", buf); 71 assert(!fclose(fp)); 72 73 // 2. write-only variant 74 fp = fwopen2(&cookie_var, f_write); 75 assert(fp); 76 assert(fileno(fp) == -1); 77 assert(fputs("test", fp) >= 0); 78 assert(!fclose(fp)); 79 80 // 3. read+write+close 81 fp = funopen2(&cookie_var, f_read, f_write, NULL, NULL, f_close); 82 assert(fp); 83 assert(fileno(fp) == -1); 84 assert(fgets(buf, sizeof(buf), fp)); 85 printf("READ: %s", buf); 86 assert(fputs("test", fp) >= 0); 87 assert(!fflush(fp)); 88 assert(!fclose(fp)); 89 90 // 4. read+seek 91 fp = funopen2(&cookie_var, f_read, NULL, f_seek, NULL, NULL); 92 assert(fp); 93 assert(fileno(fp) == -1); 94 assert(fseek(fp, 100, SEEK_SET) == 0); 95 assert(fgets(buf, sizeof(buf), fp)); 96 printf("READ: %s", buf); 97 assert(!fclose(fp)); 98 99 // 5. write+flush 100 fp = funopen2(&cookie_var, NULL, f_write, NULL, f_flush, NULL); 101 assert(fp); 102 assert(fileno(fp) == -1); 103 assert(fputs("test", fp) >= 0); 104 assert(!fflush(fp)); 105 assert(fputs("test", fp) >= 0); 106 // NB: fclose() also implicitly calls flush 107 assert(!fclose(fp)); 108 109 return 0; 110 } 111