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 //
14 // UNSUPPORTED: linux, darwin, solaris
15 
16 #include <assert.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 int cookie_var;
22 
f_read(void * cookie,char * buf,int len)23 int f_read(void *cookie, char *buf, int len) {
24   assert(cookie == &cookie_var);
25   assert(len >= 6);
26   printf("READ CALLED; len=%d\n", len);
27   return strlcpy(buf, "test\n", len);
28 }
29 
f_write(void * cookie,const char * buf,int len)30 int f_write(void *cookie, const char *buf, int len) {
31   assert(cookie == &cookie_var);
32   char *data = strndup(buf, len);
33   assert(data);
34   printf("WRITE CALLED: %s\n", data);
35   free(data);
36   return len;
37 }
38 
f_seek(void * cookie,off_t off,int whence)39 off_t f_seek(void *cookie, off_t off, int whence) {
40   assert(cookie == &cookie_var);
41   assert(whence == SEEK_SET);
42   printf("SEEK CALLED; off=%d, whence=%d\n", (int)off, whence);
43   return off;
44 }
45 
f_close(void * cookie)46 int f_close(void *cookie) {
47   assert(cookie == &cookie_var);
48   printf("CLOSE CALLED\n");
49   return 0;
50 }
51 
main(void)52 int main(void) {
53   FILE *fp;
54   char buf[10];
55 
56   // 1. read-only variant
57   fp = fropen(&cookie_var, f_read);
58   assert(fp);
59   // verify that fileno() does not crash or report nonsense
60   assert(fileno(fp) == -1);
61   assert(fgets(buf, sizeof(buf), fp));
62   printf("READ: %s", buf);
63   assert(!fclose(fp));
64 
65   // 2. write-only variant
66   fp = fwopen(&cookie_var, f_write);
67   assert(fp);
68   assert(fileno(fp) == -1);
69   assert(fputs("test", fp) >= 0);
70   assert(!fclose(fp));
71 
72   // 3. read+write+close
73   fp = funopen(&cookie_var, f_read, f_write, NULL, f_close);
74   assert(fp);
75   assert(fileno(fp) == -1);
76   assert(fgets(buf, sizeof(buf), fp));
77   printf("READ: %s", buf);
78   assert(fputs("test", fp) >= 0);
79   assert(!fclose(fp));
80 
81   // 4. read+seek
82   fp = funopen(&cookie_var, f_read, NULL, f_seek, NULL);
83   assert(fp);
84   assert(fileno(fp) == -1);
85   assert(fseek(fp, 100, SEEK_SET) == 0);
86   assert(fgets(buf, sizeof(buf), fp));
87   printf("READ: %s", buf);
88   assert(!fclose(fp));
89 
90   return 0;
91 }
92