xref: /original-bsd/usr.bin/tail/read.c (revision e59fb703)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * 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	5.1 (Berkeley) 07/21/91";
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 	long 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("%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 
58 	if (rflag) {
59 		for (t = p - 1, len = 0; t >= sp; --t, ++len)
60 			if (*t == '\n' && len) {
61 				WR(t + 1, len);
62 				len = 0;
63 		}
64 		if (wrap) {
65 			tlen = len;
66 			for (t = ep - 1, len = 0; t >= p; --t, ++len)
67 				if (*t == '\n') {
68 					if (len) {
69 						WR(t + 1, len);
70 						len = 0;
71 					}
72 					if (tlen) {
73 						WR(sp, tlen);
74 						tlen = 0;
75 					}
76 				}
77 			if (len)
78 				WR(t + 1, len);
79 			if (tlen)
80 				WR(sp, tlen);
81 		}
82 	} else {
83 		if (wrap && (len = ep - p))
84 			WR(p, len);
85 		if (len = p - sp)
86 			WR(sp, len);
87 	}
88 }
89 
90 /*
91  * lines -- read lines to an offset from the end and display.
92  *
93  * This is the function that reads to a line offset from the end of the input,
94  * storing the data in an array of buffers which is then displayed.  If the
95  * rflag is set, the data is displayed in lines in reverse order, and this
96  * routine has the usual nastiness of trying to find the newlines.  Otherwise,
97  * it is displayed from the line closest to the beginning of the input to
98  * the end.
99  */
100 void
101 lines(fp, off)
102 	register FILE *fp;
103 	long off;
104 {
105 	struct {
106 		u_int blen;
107 		u_int len;
108 		char *l;
109 	} *lines;
110 	register int ch;
111 	register char *p;
112 	u_int blen, cnt, recno;
113 	int wrap;
114 	char *sp;
115 
116 	if ((lines = malloc(off * sizeof(*lines))) == NULL)
117 		err("%s", strerror(errno));
118 
119 	sp = NULL;
120 	blen = cnt = recno = wrap = 0;
121 
122 	while ((ch = getc(fp)) != EOF) {
123 		if (++cnt > blen) {
124 			if ((sp = realloc(sp, blen += 1024)) == NULL)
125 				err("%s", strerror(errno));
126 			p = sp + cnt - 1;
127 		}
128 		*p++ = ch;
129 		if (ch == '\n') {
130 			if (lines[recno].blen < cnt) {
131 				lines[recno].blen = cnt + 256;
132 				if ((lines[recno].l = realloc(lines[recno].l,
133 				    lines[recno].blen)) == NULL)
134 					err("%s", strerror(errno));
135 			}
136 			bcopy(sp, lines[recno].l, lines[recno].len = cnt);
137 			cnt = 0;
138 			p = sp;
139 			if (++recno == off) {
140 				wrap = 1;
141 				recno = 0;
142 			}
143 		}
144 	}
145 	if (ferror(fp))
146 		ierr();
147 	if (cnt) {
148 		lines[recno].l = sp;
149 		lines[recno].len = cnt;
150 		if (++recno == off) {
151 			wrap = 1;
152 			recno = 0;
153 		}
154 	}
155 
156 	if (rflag) {
157 		for (cnt = recno - 1; cnt >= 0; --cnt)
158 			WR(lines[cnt].l, lines[cnt].len);
159 		if (wrap)
160 			for (cnt = off - 1; cnt >= recno; --cnt)
161 				WR(lines[cnt].l, lines[cnt].len);
162 	} else {
163 		if (wrap)
164 			for (cnt = recno; cnt < off; ++cnt)
165 				WR(lines[cnt].l, lines[cnt].len);
166 		for (cnt = 0; cnt < recno; ++cnt)
167 			WR(lines[cnt].l, lines[cnt].len);
168 	}
169 }
170