// RUN: %clangxx -g %s -o %t && %run %t | FileCheck %s // CHECK: READ CALLED; len={{[0-9]*}} // CHECK-NEXT: READ: test // CHECK-NEXT: WRITE CALLED: test // CHECK-NEXT: READ CALLED; len={{[0-9]*}} // CHECK-NEXT: READ: test // CHECK-NEXT: WRITE CALLED: test // CHECK-NEXT: CLOSE CALLED // CHECK-NEXT: SEEK CALLED; off=100, whence=0 // CHECK-NEXT: READ CALLED; len={{[0-9]*}} // CHECK-NEXT: READ: test // // UNSUPPORTED: linux, darwin, solaris #include #include #include #include int cookie_var; int f_read(void *cookie, char *buf, int len) { assert(cookie == &cookie_var); assert(len >= 6); printf("READ CALLED; len=%d\n", len); return strlcpy(buf, "test\n", len); } int f_write(void *cookie, const char *buf, int len) { assert(cookie == &cookie_var); char *data = strndup(buf, len); assert(data); printf("WRITE CALLED: %s\n", data); free(data); return len; } off_t f_seek(void *cookie, off_t off, int whence) { assert(cookie == &cookie_var); assert(whence == SEEK_SET); printf("SEEK CALLED; off=%d, whence=%d\n", (int)off, whence); return off; } int f_close(void *cookie) { assert(cookie == &cookie_var); printf("CLOSE CALLED\n"); return 0; } int main(void) { FILE *fp; char buf[10]; // 1. read-only variant fp = fropen(&cookie_var, f_read); assert(fp); // verify that fileno() does not crash or report nonsense assert(fileno(fp) == -1); assert(fgets(buf, sizeof(buf), fp)); printf("READ: %s", buf); assert(!fclose(fp)); // 2. write-only variant fp = fwopen(&cookie_var, f_write); assert(fp); assert(fileno(fp) == -1); assert(fputs("test", fp) >= 0); assert(!fclose(fp)); // 3. read+write+close fp = funopen(&cookie_var, f_read, f_write, NULL, f_close); assert(fp); assert(fileno(fp) == -1); assert(fgets(buf, sizeof(buf), fp)); printf("READ: %s", buf); assert(fputs("test", fp) >= 0); assert(!fclose(fp)); // 4. read+seek fp = funopen(&cookie_var, f_read, NULL, f_seek, NULL); assert(fp); assert(fileno(fp) == -1); assert(fseek(fp, 100, SEEK_SET) == 0); assert(fgets(buf, sizeof(buf), fp)); printf("READ: %s", buf); assert(!fclose(fp)); return 0; }