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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/types.h>
34#include <sys/stat.h>
35
36#include <err.h>
37#include <errno.h>
38#include <fcntl.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <strings.h>
43#include <unistd.h>
44
45#include "extern.h"
46
47/*
48 * bytes -- read bytes to an offset from the end and display.
49 *
50 * This is the function that reads to a byte offset from the end of the input,
51 * storing the data in a wrap-around buffer which is then displayed.  If the
52 * rflag is set, the data is displayed in lines in reverse order, and this
53 * routine has the usual nastiness of trying to find the newlines.  Otherwise,
54 * it is displayed from the character closest to the beginning of the input to
55 * the end.
56 */
57int
58bytes(FILE *fp, const char *fn, off_t off)
59{
60	int ch, len, tlen;
61	char *ep, *p, *t;
62	int wrap;
63	char *sp;
64
65	if ((sp = p = malloc(off)) == NULL)
66		err(1, "malloc");
67
68	for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF; ) {
69		*p = ch;
70		if (++p == ep) {
71			wrap = 1;
72			p = sp;
73		}
74	}
75	if (ferror(fp)) {
76		ierr(fn);
77		free(sp);
78		return (1);
79	}
80
81	if (rflag) {
82		for (t = p - 1, len = 0; t >= sp; --t, ++len)
83			if (*t == '\n' && len) {
84				WR(t + 1, len);
85				len = 0;
86		}
87		if (wrap) {
88			tlen = len;
89			for (t = ep - 1, len = 0; t >= p; --t, ++len)
90				if (*t == '\n') {
91					if (len) {
92						WR(t + 1, len);
93						len = 0;
94					}
95					if (tlen) {
96						WR(sp, tlen);
97						tlen = 0;
98					}
99				}
100			if (len)
101				WR(t + 1, len);
102			if (tlen)
103				WR(sp, tlen);
104		}
105	} else {
106		if (wrap && (len = ep - p))
107			WR(p, len);
108		len = p - sp;
109		if (len)
110			WR(sp, len);
111	}
112
113	free(sp);
114	return (0);
115}
116
117/*
118 * lines -- read lines to an offset from the end and display.
119 *
120 * This is the function that reads to a line offset from the end of the input,
121 * storing the data in an array of buffers which is then displayed.  If the
122 * rflag is set, the data is displayed in lines in reverse order, and this
123 * routine has the usual nastiness of trying to find the newlines.  Otherwise,
124 * it is displayed from the line closest to the beginning of the input to
125 * the end.
126 */
127int
128lines(FILE *fp, const char *fn, off_t off)
129{
130	struct {
131		int blen;
132		uint_t len;
133		char *l;
134	} *llines;
135	int ch, rc;
136	char *p, *sp;
137	int blen, cnt, recno, wrap;
138
139	if ((llines = malloc(off * sizeof (*llines))) == NULL)
140		err(1, "malloc");
141	bzero(llines, off * sizeof (*llines));
142	p = sp = NULL;
143	blen = cnt = recno = wrap = 0;
144	rc = 0;
145
146	while ((ch = getc(fp)) != EOF) {
147		if (++cnt > blen) {
148			if ((sp = realloc(sp, blen += 1024)) == NULL)
149				err(1, "realloc");
150			p = sp + cnt - 1;
151		}
152		*p++ = ch;
153		if (ch == '\n') {
154			if ((int)llines[recno].blen < cnt) {
155				llines[recno].blen = cnt + 256;
156				if ((llines[recno].l = realloc(llines[recno].l,
157				    llines[recno].blen)) == NULL)
158					err(1, "realloc");
159			}
160			bcopy(sp, llines[recno].l, llines[recno].len = cnt);
161			cnt = 0;
162			p = sp;
163			if (++recno == off) {
164				wrap = 1;
165				recno = 0;
166			}
167		}
168	}
169	if (ferror(fp)) {
170		ierr(fn);
171		rc = 1;
172		goto done;
173	}
174	if (cnt) {
175		llines[recno].l = sp;
176		sp = NULL;
177		llines[recno].len = cnt;
178		if (++recno == off) {
179			wrap = 1;
180			recno = 0;
181		}
182	}
183
184	if (rflag) {
185		for (cnt = recno - 1; cnt >= 0; --cnt)
186			WR(llines[cnt].l, llines[cnt].len);
187		if (wrap)
188			for (cnt = off - 1; cnt >= recno; --cnt)
189				WR(llines[cnt].l, llines[cnt].len);
190	} else {
191		if (wrap)
192			for (cnt = recno; cnt < off; ++cnt)
193				WR(llines[cnt].l, llines[cnt].len);
194		for (cnt = 0; cnt < recno; ++cnt)
195			WR(llines[cnt].l, llines[cnt].len);
196	}
197done:
198	for (cnt = 0; cnt < off; cnt++)
199		free(llines[cnt].l);
200	free(sp);
201	free(llines);
202	return (rc);
203}
204