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
23int cookie_var;
24
25ssize_t f_read(void *cookie, void *buf, size_t len) {
26 assert(cookie == &cookie_var);
27 assert(len >= 6);
28 printf(format: "READ CALLED; len=%zd\n", len);
29 return strlcpy(dest: (char*)buf, src: "test\n", n: len);
30}
31
32ssize_t f_write(void *cookie, const void *buf, size_t len) {
33 assert(cookie == &cookie_var);
34 char *data = strndup(string: (char*)buf, n: len);
35 assert(data);
36 printf(format: "WRITE CALLED: %s\n", data);
37 free(ptr: data);
38 return len;
39}
40
41off_t f_seek(void *cookie, off_t off, int whence) {
42 assert(cookie == &cookie_var);
43 assert(whence == SEEK_SET);
44 printf(format: "SEEK CALLED; off=%d, whence=%d\n", (int)off, whence);
45 return off;
46}
47
48int f_flush(void *cookie) {
49 assert(cookie == &cookie_var);
50 printf(format: "FLUSH CALLED\n");
51 return 0;
52}
53
54int f_close(void *cookie) {
55 assert(cookie == &cookie_var);
56 printf(format: "CLOSE CALLED\n");
57 return 0;
58}
59
60int 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(format: "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(format: "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(format: "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

source code of compiler-rt/test/sanitizer_common/TestCases/NetBSD/funopen2.cpp