read.c revision 69552
129347Speter/*-
229347Speter * Copyright (c) 1991, 1993
329347Speter *	The Regents of the University of California.  All rights reserved.
429347Speter *
529347Speter * This code is derived from software contributed to Berkeley by
629347Speter * Edward Sze-Tyan Wang.
729347Speter *
829347Speter * Redistribution and use in source and binary forms, with or without
929347Speter * modification, are permitted provided that the following conditions
1029347Speter * are met:
1129347Speter * 1. Redistributions of source code must retain the above copyright
1229347Speter *    notice, this list of conditions and the following disclaimer.
1329347Speter * 2. Redistributions in binary form must reproduce the above copyright
1429347Speter *    notice, this list of conditions and the following disclaimer in the
1529347Speter *    documentation and/or other materials provided with the distribution.
1629347Speter * 3. All advertising materials mentioning features or use of this software
1729347Speter *    must display the following acknowledgement:
1829347Speter *	This product includes software developed by the University of
1929347Speter *	California, Berkeley and its contributors.
2029347Speter * 4. Neither the name of the University nor the names of its contributors
2129347Speter *    may be used to endorse or promote products derived from this software
2229347Speter *    without specific prior written permission.
2329347Speter *
2429347Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2529347Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2629347Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2729347Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2850477Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2929347Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3029347Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3129347Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3229347Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3329347Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3499593Smike * SUCH DAMAGE.
3599593Smike */
3629347Speter
3772093Sasmodai#ifndef lint
3829347Speter#if 0
3929347Speterstatic char sccsid[] = "@(#)read.c	8.1 (Berkeley) 6/6/93";
4099593Smike#endif
4199593Smikestatic const char rcsid[] =
4229347Speter  "$FreeBSD: head/usr.bin/tail/read.c 69552 2000-12-03 17:05:45Z asmodai $";
4333059Sbde#endif /* not lint */
4429347Speter
4529347Speter#include <sys/types.h>
4629347Speter#include <sys/stat.h>
4729347Speter#include <fcntl.h>
4829347Speter#include <errno.h>
4929347Speter#include <unistd.h>
5029347Speter#include <stdio.h>
5129347Speter#include <stdlib.h>
5229347Speter#include <string.h>
5329347Speter#include <err.h>
5429347Speter#include "extern.h"
5529347Speter
5629347Speter/*
5729347Speter * bytes -- read bytes to an offset from the end and display.
5829347Speter *
5929347Speter * This is the function that reads to a byte offset from the end of the input,
6029347Speter * storing the data in a wrap-around buffer which is then displayed.  If the
6129347Speter * rflag is set, the data is displayed in lines in reverse order, and this
6229347Speter * routine has the usual nastiness of trying to find the newlines.  Otherwise,
6329347Speter * it is displayed from the character closest to the beginning of the input to
6429347Speter * the end.
6529347Speter */
6629347Speterint
6729347Speterbytes(fp, off)
6829347Speter	FILE *fp;
6999710Smike	off_t off;
7094997Salfred{
7194997Salfred	int ch, len, tlen;
7299593Smike	char *ep, *p, *t;
7331727Swollman	int wrap;
7431727Swollman	char *sp;
7529347Speter
7629347Speter	if ((sp = p = malloc(off)) == NULL)
7729347Speter		err(1, "malloc");
7829347Speter
7929347Speter	for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) {
8029347Speter		*p = ch;
8129347Speter		if (++p == ep) {
8299593Smike			wrap = 1;
8399593Smike			p = sp;
8431727Swollman		}
8531727Swollman	}
8631727Swollman	if (ferror(fp)) {
8729373Speter		ierr();
8833059Sbde		return 1;
8933059Sbde	}
9033059Sbde
9129373Speter	if (rflag) {
9233059Sbde		for (t = p - 1, len = 0; t >= sp; --t, ++len)
9329373Speter			if (*t == '\n' && len) {
9499593Smike				WR(t + 1, len);
9599593Smike				len = 0;
9655205Speter		}
9733059Sbde		if (wrap) {
98275986Sdchagin			tlen = len;
99275986Sdchagin			for (t = ep - 1, len = 0; t >= p; --t, ++len)
100275986Sdchagin				if (*t == '\n') {
101275986Sdchagin					if (len) {
102275986Sdchagin						WR(t + 1, len);
103275986Sdchagin						len = 0;
104275986Sdchagin					}
105275986Sdchagin					if (tlen) {
106275986Sdchagin						WR(sp, tlen);
107275986Sdchagin						tlen = 0;
108275986Sdchagin					}
109275986Sdchagin				}
110275986Sdchagin			if (len)
11129347Speter				WR(t + 1, len);
11299593Smike			if (tlen)
113275986Sdchagin				WR(sp, tlen);
114275986Sdchagin		}
115275986Sdchagin	} else {
116275986Sdchagin		if (wrap && (len = ep - p))
117275986Sdchagin			WR(p, len);
11829347Speter		if (len = p - sp)
11929347Speter			WR(sp, len);
12055205Speter	}
12133059Sbde	return 0;
12229347Speter}
123
124/*
125 * lines -- read lines to an offset from the end and display.
126 *
127 * This is the function that reads to a line offset from the end of the input,
128 * storing the data in an array of buffers which is then displayed.  If the
129 * rflag is set, the data is displayed in lines in reverse order, and this
130 * routine has the usual nastiness of trying to find the newlines.  Otherwise,
131 * it is displayed from the line closest to the beginning of the input to
132 * the end.
133 */
134int
135lines(fp, off)
136	FILE *fp;
137	off_t off;
138{
139	struct {
140		u_int blen;
141		u_int len;
142		char *l;
143	} *lines;
144	int ch;
145	char *p;
146	int blen, cnt, recno, wrap;
147	char *sp;
148
149	if ((lines = malloc(off * sizeof(*lines))) == NULL)
150		err(1, "malloc");
151	bzero(lines, off * sizeof(*lines));
152	sp = NULL;
153	blen = cnt = recno = wrap = 0;
154
155	while ((ch = getc(fp)) != EOF) {
156		if (++cnt > blen) {
157			if ((sp = realloc(sp, blen += 1024)) == NULL)
158				err(1, "realloc");
159			p = sp + cnt - 1;
160		}
161		*p++ = ch;
162		if (ch == '\n') {
163			if (lines[recno].blen < cnt) {
164				lines[recno].blen = cnt + 256;
165				if ((lines[recno].l = realloc(lines[recno].l,
166				    lines[recno].blen)) == NULL)
167					err(1, "realloc");
168			}
169			bcopy(sp, lines[recno].l, lines[recno].len = cnt);
170			cnt = 0;
171			p = sp;
172			if (++recno == off) {
173				wrap = 1;
174				recno = 0;
175			}
176		}
177	}
178	if (ferror(fp)) {
179		ierr();
180		return 1;
181	}
182	if (cnt) {
183		lines[recno].l = sp;
184		lines[recno].len = cnt;
185		if (++recno == off) {
186			wrap = 1;
187			recno = 0;
188		}
189	}
190
191	if (rflag) {
192		for (cnt = recno - 1; cnt >= 0; --cnt)
193			WR(lines[cnt].l, lines[cnt].len);
194		if (wrap)
195			for (cnt = off - 1; cnt >= recno; --cnt)
196				WR(lines[cnt].l, lines[cnt].len);
197	} else {
198		if (wrap)
199			for (cnt = recno; cnt < off; ++cnt)
200				WR(lines[cnt].l, lines[cnt].len);
201		for (cnt = 0; cnt < recno; ++cnt)
202			WR(lines[cnt].l, lines[cnt].len);
203	}
204	return 0;
205}
206