Introduction
Introduction Statistics Contact Development Disclaimer Help
tail.c - sbase - suckless unix tools
git clone git://git.suckless.org/sbase
Log
Files
Refs
README
LICENSE
---
tail.c (4355B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <sys/stat.h>
3
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11
12 #include "utf.h"
13 #include "util.h"
14
15 static char mode = 'n';
16
17 static int
18 dropinit(int fd, const char *fname, size_t count)
19 {
20 Rune r;
21 char buf[BUFSIZ], *p;
22 ssize_t n;
23 int nr;
24
25 if (count < 2)
26 goto copy;
27 count--; /* numbering starts at 1 */
28 while (count && (n = read(fd, buf, sizeof(buf))) > 0) {
29 switch (mode) {
30 case 'n': /* lines */
31 for (p = buf; count && n > 0; p++, n--) {
32 if (*p == '\n')
33 count--;
34 }
35 break;
36 case 'c': /* bytes */
37 if (count > n) {
38 count -= n;
39 } else {
40 p = buf + count;
41 n -= count;
42 count = 0;
43 }
44 break;
45 case 'm': /* runes */
46 for (p = buf; count && n > 0; p += nr, n -= nr, …
47 nr = charntorune(&r, p, n);
48 if (!nr) {
49 /* we don't have a full rune, mo…
50 * remaining data to beginning a…
51 * again */
52 memmove(buf, p, n);
53 break;
54 }
55 }
56 break;
57 }
58 }
59 if (count) {
60 if (n < 0)
61 weprintf("read %s:", fname);
62 if (n <= 0)
63 return n;
64 }
65
66 /* write the rest of the buffer */
67 if (writeall(1, p, n) < 0)
68 eprintf("write:");
69 copy:
70 switch (concat(fd, fname, 1, "<stdout>")) {
71 case -1: /* read error */
72 return -1;
73 case -2: /* write error */
74 exit(1);
75 default:
76 return 0;
77 }
78 }
79
80 static int
81 taketail(int fd, const char *fname, size_t count)
82 {
83 static char *buf = NULL;
84 static size_t size = 0;
85 char *p;
86 size_t len = 0, left;
87 ssize_t n;
88
89 if (!count)
90 return 0;
91 for (;;) {
92 if (len + BUFSIZ > size) {
93 /* make sure we have at least BUFSIZ to read */
94 size += 2 * BUFSIZ;
95 buf = erealloc(buf, size);
96 }
97 n = read(fd, buf + len, size - len);
98 if (n < 0) {
99 weprintf("read %s:", fname);
100 return -1;
101 }
102 if (n == 0)
103 break;
104 len += n;
105 switch (mode) {
106 case 'n': /* lines */
107 /* ignore the last character; if it is a newline…
108 * ends the last line */
109 for (p = buf + len - 2, left = count; p >= buf; …
110 if (*p != '\n')
111 continue;
112 left--;
113 if (!left) {
114 p++;
115 break;
116 }
117 }
118 break;
119 case 'c': /* bytes */
120 p = count < len ? buf + len - count : buf;
121 break;
122 case 'm': /* runes */
123 for (p = buf + len - 1, left = count; p >= buf; …
124 /* skip utf-8 continuation bytes */
125 if (UTF8_POINT(*p))
126 continue;
127 left--;
128 if (!left)
129 break;
130 }
131 break;
132 }
133 if (p > buf) {
134 len -= p - buf;
135 memmove(buf, p, len);
136 }
137 }
138 if (writeall(1, buf, len) < 0)
139 eprintf("write:");
140 return 0;
141 }
142
143 static void
144 usage(void)
145 {
146 eprintf("usage: %s [-f] [-c num | -m num | -n num | -num] [file …
147 }
148
149 int
150 main(int argc, char *argv[])
151 {
152 struct stat st1, st2;
153 int fd;
154 size_t n = 10;
155 int fflag = 0, ret = 0, newline = 0, many = 0;
156 char *numstr;
157 int (*tail)(int, const char *, size_t) = taketail;
158
159 ARGBEGIN {
160 case 'f':
161 fflag = 1;
162 break;
163 case 'c':
164 case 'm':
165 case 'n':
166 mode = ARGC();
167 numstr = EARGF(usage());
168 n = MIN(llabs(estrtonum(numstr, LLONG_MIN + 1,
169 MIN(LLONG_MAX, SIZE_MAX))), SIZE…
170 if (strchr(numstr, '+'))
171 tail = dropinit;
172 break;
173 ARGNUM:
174 n = ARGNUMF();
175 break;
176 default:
177 usage();
178 } ARGEND
179
180 if (!argc) {
181 if (tail(0, "<stdin>", n) < 0)
182 ret = 1;
183 } else {
184 if ((many = argc > 1) && fflag)
185 usage();
186 for (newline = 0; *argv; argc--, argv++) {
187 if (!strcmp(*argv, "-")) {
188 *argv = "<stdin>";
189 fd = 0;
190 } else if ((fd = open(*argv, O_RDONLY)) < 0) {
191 weprintf("open %s:", *argv);
192 ret = 1;
193 continue;
194 }
195 if (many)
196 printf("%s==> %s <==\n", newline ? "\n" …
197 if (fstat(fd, &st1) < 0)
198 eprintf("fstat %s:", *argv);
199 if (!(S_ISFIFO(st1.st_mode) || S_ISREG(st1.st_mo…
200 fflag = 0;
201 newline = 1;
202 if (tail(fd, *argv, n) < 0) {
203 ret = 1;
204 fflag = 0;
205 }
206
207 if (!fflag) {
208 if (fd != 0)
209 close(fd);
210 continue;
211 }
212 for (;;) {
213 if (concat(fd, *argv, 1, "<stdout>") < 0)
214 exit(1);
215 if (fstat(fd, &st2) < 0)
216 eprintf("fstat %s:", *argv);
217 if (st2.st_size < st1.st_size) {
218 fprintf(stderr, "%s: file trunca…
219 if (lseek(fd, SEEK_SET, 0) < 0)
220 eprintf("lseek:");
221 }
222 st1 = st2;
223 sleep(1);
224 }
225 }
226 }
227
228 return ret;
229 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.