blind-peek-head.c - blind - suckless command-line video editing utility | |
git clone git://git.suckless.org/blind | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
blind-peek-head.c (3073B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include "common.h" | |
3 | |
4 USAGE("") | |
5 | |
6 static ssize_t | |
7 peek_socket(char *buf, size_t n) | |
8 { | |
9 ssize_t r = recv(STDIN_FILENO, buf, n, MSG_PEEK); | |
10 if (r < 0 && errno != ENOTSOCK) | |
11 eprintf("recv <stdin>:"); | |
12 return r; | |
13 } | |
14 | |
15 static ssize_t | |
16 peek_regular(char *buf, size_t n) | |
17 { | |
18 ssize_t r; | |
19 off_t pos = lseek(STDIN_FILENO, 0, SEEK_CUR); | |
20 if (pos < 0) { | |
21 if (errno != ESPIPE) | |
22 eprintf("lseek <stdin>:"); | |
23 return -1; | |
24 } | |
25 r = pread(STDIN_FILENO, buf, n, pos); | |
26 if (r < 0 && errno != ESPIPE) | |
27 eprintf("pread <stdin>:"); | |
28 return r; | |
29 } | |
30 | |
31 #if defined(HAVE_TEE) | |
32 static ssize_t | |
33 peek_pipe(char *buf, size_t n) | |
34 { | |
35 int rw[2]; | |
36 ssize_t m; | |
37 size_t p; | |
38 if (pipe(rw)) | |
39 eprintf("pipe"); | |
40 m = tee(STDIN_FILENO, rw[1], n, 0); | |
41 if (m < 0) { | |
42 if (errno != EINVAL) | |
43 eprintf("tee <stdin>:"); | |
44 return -1; | |
45 } | |
46 close(rw[1]); | |
47 p = ereadall(rw[0], buf, (size_t)m, "<pipe>"); | |
48 close(rw[0]); | |
49 return (ssize_t)p; | |
50 } | |
51 #endif | |
52 | |
53 static size_t | |
54 peek(char *buf, size_t n) | |
55 { | |
56 static int method = 0; | |
57 ssize_t r; | |
58 switch (method) { | |
59 case 0: | |
60 if ((r = peek_socket(buf, n)) >= 0) | |
61 return (size_t)r; | |
62 method++; | |
63 /* fall-through */ | |
64 case 1: | |
65 if ((r = peek_regular(buf, n)) >= 0) | |
66 return (size_t)r; | |
67 method++; | |
68 #if defined(HAVE_TEE) | |
69 /* fall-through */ | |
70 default: | |
71 if ((r = peek_pipe(buf, n)) >= 0) | |
72 return (size_t)r; | |
73 eprintf("can only peek pipes, sockets, and regular files… | |
74 #else | |
75 eprintf("can only peek sockets and regular files\n"); | |
76 #endif | |
77 } | |
78 } | |
79 | |
80 int | |
81 main(int argc, char *argv[]) | |
82 { | |
83 char buf[STREAM_HEAD_MAX], *p; | |
84 char magic[] = {'\0', 'u', 'i', 'v', 'f'}; | |
85 size_t i, len = 0, last_len; | |
86 #if defined(HAVE_EPOLL) | |
87 struct epoll_event ev; | |
88 int epfd, epr = 0; | |
89 #endif | |
90 | |
91 UNOFLAGS(argc); | |
92 | |
93 #if defined(HAVE_EPOLL) | |
94 epfd = epoll_create1(0); | |
95 if (epfd < 0) | |
96 eprintf("epoll_create1:"); | |
97 | |
98 memset(&ev, 0, sizeof(ev)); | |
99 ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET; | |
100 if (epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev)) | |
101 eprintf("epoll_ctl EPOLL_CTL_ADD:"); | |
102 | |
103 do { | |
104 last_len = len; | |
105 len = peek(buf, sizeof(buf)); | |
106 p = memchr(buf, '\n', len); | |
107 if (p && len >= (size_t)(++p - buf) + ELEMENTSOF(magic)) | |
108 goto ready; | |
109 } while (len > last_len && (epr = epoll_wait(epfd, &ev, 1, -1)) … | |
110 if (epr < 0) | |
111 eprintf("epoll_wait:"); | |
112 #else | |
113 goto beginning; | |
114 do { | |
115 usleep(50000); | |
116 beginning: | |
117 last_len = len; | |
118 len = peek(buf, sizeof(buf)); | |
119 p = memchr(buf, '\n', len); | |
120 if (p && len >= (size_t)(++p - buf) + ELEMENTSOF(magic)) | |
121 goto ready; | |
122 } while (len > last_len); | |
123 #endif | |
124 eprintf("could not read entire head\n"); | |
125 | |
126 ready: | |
127 len = (size_t)(p - buf); | |
128 for (i = 0; i < ELEMENTSOF(magic); i++) | |
129 if (p[i] != magic[i]) | |
130 goto bad_format; | |
131 p = buf; | |
132 for (i = 0; i < 3; i++) { | |
133 if (!isdigit(*p)) | |
134 goto bad_format; | |
135 while (isdigit(*p)) p++; | |
136 if (*p++ != ' ') | |
137 goto bad_format; | |
138 } | |
139 while (isalnum(*p) || *p == ' ') { | |
140 if (p[0] == ' ' && p[-1] == ' ') | |
141 goto bad_format; | |
142 p++; | |
143 } | |
144 if (p[-1] == ' ' || p[0] != '\n') | |
145 goto bad_format; | |
146 | |
147 ewriteall(STDOUT_FILENO, buf, len, "<stdout>"); | |
148 return 0; | |
149 | |
150 bad_format: | |
151 eprintf("<stdin>: file format not supported\n"); | |
152 } |