xref: /netbsd/usr.bin/tail/read.c (revision d5250e4e)
1*d5250e4eSitojun /*	$NetBSD: read.c,v 1.10 2003/10/16 06:39:56 itojun Exp $	*/
2ae646d0eSjtc 
3aa97860fSglass /*-
4ae646d0eSjtc  * Copyright (c) 1991, 1993
5ae646d0eSjtc  *	The Regents of the University of California.  All rights reserved.
6aa97860fSglass  *
7aa97860fSglass  * This code is derived from software contributed to Berkeley by
8aa97860fSglass  * Edward Sze-Tyan Wang.
9aa97860fSglass  *
10aa97860fSglass  * Redistribution and use in source and binary forms, with or without
11aa97860fSglass  * modification, are permitted provided that the following conditions
12aa97860fSglass  * are met:
13aa97860fSglass  * 1. Redistributions of source code must retain the above copyright
14aa97860fSglass  *    notice, this list of conditions and the following disclaimer.
15aa97860fSglass  * 2. Redistributions in binary form must reproduce the above copyright
16aa97860fSglass  *    notice, this list of conditions and the following disclaimer in the
17aa97860fSglass  *    documentation and/or other materials provided with the distribution.
1889aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
19aa97860fSglass  *    may be used to endorse or promote products derived from this software
20aa97860fSglass  *    without specific prior written permission.
21aa97860fSglass  *
22aa97860fSglass  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23aa97860fSglass  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24aa97860fSglass  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25aa97860fSglass  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26aa97860fSglass  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27aa97860fSglass  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28aa97860fSglass  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29aa97860fSglass  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30aa97860fSglass  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31aa97860fSglass  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32aa97860fSglass  * SUCH DAMAGE.
33aa97860fSglass  */
34aa97860fSglass 
35079884daSlukem #include <sys/cdefs.h>
36aa97860fSglass #ifndef lint
37ae646d0eSjtc #if 0
38ae646d0eSjtc static char sccsid[] = "@(#)read.c	8.1 (Berkeley) 6/6/93";
39ae646d0eSjtc #endif
40*d5250e4eSitojun __RCSID("$NetBSD: read.c,v 1.10 2003/10/16 06:39:56 itojun Exp $");
41aa97860fSglass #endif /* not lint */
42aa97860fSglass 
43aa97860fSglass #include <sys/types.h>
44aa97860fSglass #include <sys/stat.h>
45aa97860fSglass #include <fcntl.h>
46aa97860fSglass #include <errno.h>
47aa97860fSglass #include <unistd.h>
48aa97860fSglass #include <stdio.h>
49aa97860fSglass #include <stdlib.h>
50aa97860fSglass #include <string.h>
51aa97860fSglass #include "extern.h"
52aa97860fSglass 
53aa97860fSglass /*
54aa97860fSglass  * bytes -- read bytes to an offset from the end and display.
55aa97860fSglass  *
56aa97860fSglass  * This is the function that reads to a byte offset from the end of the input,
57aa97860fSglass  * storing the data in a wrap-around buffer which is then displayed.  If the
58aa97860fSglass  * rflag is set, the data is displayed in lines in reverse order, and this
59aa97860fSglass  * routine has the usual nastiness of trying to find the newlines.  Otherwise,
60aa97860fSglass  * it is displayed from the character closest to the beginning of the input to
61aa97860fSglass  * the end.
62b02d8140Scgd  *
63b02d8140Scgd  * Non-zero return means than a (non-fatal) error occurred.
64aa97860fSglass  */
65b02d8140Scgd int
663c4c9d2bSwiz bytes(FILE *fp, __off_t off)
67aa97860fSglass {
68079884daSlukem 	int ch, len, tlen;
69079884daSlukem 	char *ep, *p, *t;
70aa97860fSglass 	int wrap;
71aa97860fSglass 	char *sp;
72aa97860fSglass 
73aa97860fSglass 	if ((sp = p = malloc(off)) == NULL)
74ae646d0eSjtc 		err(1, "%s", strerror(errno));
75aa97860fSglass 
76aa97860fSglass 	for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) {
77aa97860fSglass 		*p = ch;
78aa97860fSglass 		if (++p == ep) {
79aa97860fSglass 			wrap = 1;
80aa97860fSglass 			p = sp;
81aa97860fSglass 		}
82aa97860fSglass 	}
83ae646d0eSjtc 	if (ferror(fp)) {
84aa97860fSglass 		ierr();
85b02d8140Scgd 		return (1);
86ae646d0eSjtc 	}
87aa97860fSglass 
88aa97860fSglass 	if (rflag) {
89aa97860fSglass 		for (t = p - 1, len = 0; t >= sp; --t, ++len)
90aa97860fSglass 			if (*t == '\n' && len) {
91aa97860fSglass 				WR(t + 1, len);
92aa97860fSglass 				len = 0;
93aa97860fSglass 		}
94aa97860fSglass 		if (wrap) {
95aa97860fSglass 			tlen = len;
96aa97860fSglass 			for (t = ep - 1, len = 0; t >= p; --t, ++len)
97aa97860fSglass 				if (*t == '\n') {
98aa97860fSglass 					if (len) {
99aa97860fSglass 						WR(t + 1, len);
100aa97860fSglass 						len = 0;
101aa97860fSglass 					}
102aa97860fSglass 					if (tlen) {
103aa97860fSglass 						WR(sp, tlen);
104aa97860fSglass 						tlen = 0;
105aa97860fSglass 					}
106aa97860fSglass 				}
107aa97860fSglass 			if (len)
108aa97860fSglass 				WR(t + 1, len);
109aa97860fSglass 			if (tlen)
110aa97860fSglass 				WR(sp, tlen);
111aa97860fSglass 		}
112aa97860fSglass 	} else {
113aa97860fSglass 		if (wrap && (len = ep - p))
114aa97860fSglass 			WR(p, len);
115079884daSlukem 		if ((len = p - sp) == 0)
116aa97860fSglass 			WR(sp, len);
117aa97860fSglass 	}
118b02d8140Scgd 	return (0);
119aa97860fSglass }
120aa97860fSglass 
121aa97860fSglass /*
122aa97860fSglass  * lines -- read lines to an offset from the end and display.
123aa97860fSglass  *
124aa97860fSglass  * This is the function that reads to a line offset from the end of the input,
125aa97860fSglass  * storing the data in an array of buffers which is then displayed.  If the
126aa97860fSglass  * rflag is set, the data is displayed in lines in reverse order, and this
127aa97860fSglass  * routine has the usual nastiness of trying to find the newlines.  Otherwise,
128aa97860fSglass  * it is displayed from the line closest to the beginning of the input to
129aa97860fSglass  * the end.
130b02d8140Scgd  *
131b02d8140Scgd  * Non-zero return means than a (non-fatal) error occurred.
132aa97860fSglass  */
133b02d8140Scgd int
1343c4c9d2bSwiz lines(FILE *fp, __off_t off)
135aa97860fSglass {
136aa97860fSglass 	struct {
137aa97860fSglass 		u_int blen;
138aa97860fSglass 		u_int len;
139aa97860fSglass 		char *l;
140aa97860fSglass 	} *lines;
141079884daSlukem 	int ch;
142079884daSlukem 	char *p;
143ae646d0eSjtc 	int blen, cnt, recno, wrap;
144*d5250e4eSitojun 	char *sp, *n;
145aa97860fSglass 
146079884daSlukem 	p = NULL;
147aa97860fSglass 	if ((lines = malloc(off * sizeof(*lines))) == NULL)
148ae646d0eSjtc 		err(1, "%s", strerror(errno));
149aa97860fSglass 
1507872ac63Schristos 	memset(lines, 0, sizeof(*lines) * off);
1517872ac63Schristos 
152aa97860fSglass 	sp = NULL;
153aa97860fSglass 	blen = cnt = recno = wrap = 0;
154aa97860fSglass 
155aa97860fSglass 	while ((ch = getc(fp)) != EOF) {
156aa97860fSglass 		if (++cnt > blen) {
157*d5250e4eSitojun 			if ((n = realloc(sp, blen + 1024)) == NULL)
158ae646d0eSjtc 				err(1, "%s", strerror(errno));
159*d5250e4eSitojun 			sp = n;
160*d5250e4eSitojun 			blen += 1024;
161aa97860fSglass 			p = sp + cnt - 1;
162aa97860fSglass 		}
163aa97860fSglass 		*p++ = ch;
164aa97860fSglass 		if (ch == '\n') {
165aa97860fSglass 			if (lines[recno].blen < cnt) {
166*d5250e4eSitojun 				if ((n = realloc(lines[recno].l,
167*d5250e4eSitojun 				    cnt + 256)) == NULL)
168ae646d0eSjtc 					err(1, "%s", strerror(errno));
169*d5250e4eSitojun 				lines[recno].l = n;
170*d5250e4eSitojun 				lines[recno].blen = cnt + 256;
171aa97860fSglass 			}
172079884daSlukem 			memmove(lines[recno].l, sp, lines[recno].len = cnt);
173aa97860fSglass 			cnt = 0;
174aa97860fSglass 			p = sp;
175aa97860fSglass 			if (++recno == off) {
176aa97860fSglass 				wrap = 1;
177aa97860fSglass 				recno = 0;
178aa97860fSglass 			}
179aa97860fSglass 		}
180aa97860fSglass 	}
181ae646d0eSjtc 	if (ferror(fp)) {
182aa97860fSglass 		ierr();
183b02d8140Scgd 		return (1);
184ae646d0eSjtc 	}
185aa97860fSglass 	if (cnt) {
186aa97860fSglass 		lines[recno].l = sp;
187aa97860fSglass 		lines[recno].len = cnt;
188aa97860fSglass 		if (++recno == off) {
189aa97860fSglass 			wrap = 1;
190aa97860fSglass 			recno = 0;
191aa97860fSglass 		}
192aa97860fSglass 	}
193aa97860fSglass 
194aa97860fSglass 	if (rflag) {
195aa97860fSglass 		for (cnt = recno - 1; cnt >= 0; --cnt)
196aa97860fSglass 			WR(lines[cnt].l, lines[cnt].len);
197aa97860fSglass 		if (wrap)
198aa97860fSglass 			for (cnt = off - 1; cnt >= recno; --cnt)
199aa97860fSglass 				WR(lines[cnt].l, lines[cnt].len);
200aa97860fSglass 	} else {
201aa97860fSglass 		if (wrap)
202aa97860fSglass 			for (cnt = recno; cnt < off; ++cnt)
203aa97860fSglass 				WR(lines[cnt].l, lines[cnt].len);
204aa97860fSglass 		for (cnt = 0; cnt < recno; ++cnt)
205aa97860fSglass 			WR(lines[cnt].l, lines[cnt].len);
206aa97860fSglass 	}
207b02d8140Scgd 	return (0);
208aa97860fSglass }
209