xref: /original-bsd/usr.bin/tail/read.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Edward Sze-Tyan Wang.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)read.c	8.1 (Berkeley) 06/06/93";
13 #endif /* not lint */
14 
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "extern.h"
24 
25 /*
26  * bytes -- read bytes to an offset from the end and display.
27  *
28  * This is the function that reads to a byte offset from the end of the input,
29  * storing the data in a wrap-around buffer which is then displayed.  If the
30  * rflag is set, the data is displayed in lines in reverse order, and this
31  * routine has the usual nastiness of trying to find the newlines.  Otherwise,
32  * it is displayed from the character closest to the beginning of the input to
33  * the end.
34  */
35 void
36 bytes(fp, off)
37 	register FILE *fp;
38 	off_t off;
39 {
40 	register int ch, len, tlen;
41 	register char *ep, *p, *t;
42 	int wrap;
43 	char *sp;
44 
45 	if ((sp = p = malloc(off)) == NULL)
46 		err(1, "%s", strerror(errno));
47 
48 	for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) {
49 		*p = ch;
50 		if (++p == ep) {
51 			wrap = 1;
52 			p = sp;
53 		}
54 	}
55 	if (ferror(fp)) {
56 		ierr();
57 		return;
58 	}
59 
60 	if (rflag) {
61 		for (t = p - 1, len = 0; t >= sp; --t, ++len)
62 			if (*t == '\n' && len) {
63 				WR(t + 1, len);
64 				len = 0;
65 		}
66 		if (wrap) {
67 			tlen = len;
68 			for (t = ep - 1, len = 0; t >= p; --t, ++len)
69 				if (*t == '\n') {
70 					if (len) {
71 						WR(t + 1, len);
72 						len = 0;
73 					}
74 					if (tlen) {
75 						WR(sp, tlen);
76 						tlen = 0;
77 					}
78 				}
79 			if (len)
80 				WR(t + 1, len);
81 			if (tlen)
82 				WR(sp, tlen);
83 		}
84 	} else {
85 		if (wrap && (len = ep - p))
86 			WR(p, len);
87 		if (len = p - sp)
88 			WR(sp, len);
89 	}
90 }
91 
92 /*
93  * lines -- read lines to an offset from the end and display.
94  *
95  * This is the function that reads to a line offset from the end of the input,
96  * storing the data in an array of buffers which is then displayed.  If the
97  * rflag is set, the data is displayed in lines in reverse order, and this
98  * routine has the usual nastiness of trying to find the newlines.  Otherwise,
99  * it is displayed from the line closest to the beginning of the input to
100  * the end.
101  */
102 void
103 lines(fp, off)
104 	register FILE *fp;
105 	off_t off;
106 {
107 	struct {
108 		u_int blen;
109 		u_int len;
110 		char *l;
111 	} *lines;
112 	register int ch;
113 	register char *p;
114 	int blen, cnt, recno, wrap;
115 	char *sp;
116 
117 	if ((lines = malloc(off * sizeof(*lines))) == NULL)
118 		err(1, "%s", strerror(errno));
119 
120 	sp = NULL;
121 	blen = cnt = recno = wrap = 0;
122 
123 	while ((ch = getc(fp)) != EOF) {
124 		if (++cnt > blen) {
125 			if ((sp = realloc(sp, blen += 1024)) == NULL)
126 				err(1, "%s", strerror(errno));
127 			p = sp + cnt - 1;
128 		}
129 		*p++ = ch;
130 		if (ch == '\n') {
131 			if (lines[recno].blen < cnt) {
132 				lines[recno].blen = cnt + 256;
133 				if ((lines[recno].l = realloc(lines[recno].l,
134 				    lines[recno].blen)) == NULL)
135 					err(1, "%s", strerror(errno));
136 			}
137 			bcopy(sp, lines[recno].l, lines[recno].len = cnt);
138 			cnt = 0;
139 			p = sp;
140 			if (++recno == off) {
141 				wrap = 1;
142 				recno = 0;
143 			}
144 		}
145 	}
146 	if (ferror(fp)) {
147 		ierr();
148 		return;
149 	}
150 	if (cnt) {
151 		lines[recno].l = sp;
152 		lines[recno].len = cnt;
153 		if (++recno == off) {
154 			wrap = 1;
155 			recno = 0;
156 		}
157 	}
158 
159 	if (rflag) {
160 		for (cnt = recno - 1; cnt >= 0; --cnt)
161 			WR(lines[cnt].l, lines[cnt].len);
162 		if (wrap)
163 			for (cnt = off - 1; cnt >= recno; --cnt)
164 				WR(lines[cnt].l, lines[cnt].len);
165 	} else {
166 		if (wrap)
167 			for (cnt = recno; cnt < off; ++cnt)
168 				WR(lines[cnt].l, lines[cnt].len);
169 		for (cnt = 0; cnt < recno; ++cnt)
170 			WR(lines[cnt].l, lines[cnt].len);
171 	}
172 }
173