xref: /netbsd/usr.bin/tail/read.c (revision 2a6f4060)
1*2a6f4060Schristos /*	$NetBSD: read.c,v 1.17 2011/09/03 10:59:10 christos 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*2a6f4060Schristos __RCSID("$NetBSD: read.c,v 1.17 2011/09/03 10:59:10 christos 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 /*
540980aab5Slukem  * displaybytes -- 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
displaybytes(FILE * fp,off_t off)660980aab5Slukem displaybytes(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)
744917bba2Schristos 		xerr(1, "malloc");
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();
85*2a6f4060Schristos 		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);
1150523aae7Schristos 		if ((len = p - sp) != 0)
116aa97860fSglass 			WR(sp, len);
117aa97860fSglass 	}
118*2a6f4060Schristos 	return 0;
119aa97860fSglass }
120aa97860fSglass 
121aa97860fSglass /*
1220980aab5Slukem  * displaylines -- 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
displaylines(FILE * fp,off_t off)1340980aab5Slukem displaylines(FILE *fp, off_t off)
135aa97860fSglass {
136aa97860fSglass 	struct {
1370980aab5Slukem 		int blen;
1380980aab5Slukem 		int len;
139aa97860fSglass 		char *l;
140aa97860fSglass 	} *lines;
141079884daSlukem 	int ch;
142079884daSlukem 	char *p;
143ae646d0eSjtc 	int blen, cnt, recno, wrap;
144d5250e4eSitojun 	char *sp, *n;
145aa97860fSglass 
146079884daSlukem 	p = NULL;
147aa97860fSglass 	if ((lines = malloc(off * sizeof(*lines))) == NULL)
1484917bba2Schristos 		xerr(1, "malloc");
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) {
157d5250e4eSitojun 			if ((n = realloc(sp, blen + 1024)) == NULL)
1584917bba2Schristos 				xerr(1, "realloc");
159d5250e4eSitojun 			sp = n;
160d5250e4eSitojun 			blen += 1024;
161aa97860fSglass 			p = sp + cnt - 1;
162aa97860fSglass 		}
163aa97860fSglass 		*p++ = ch;
164aa97860fSglass 		if (ch == '\n') {
165aa97860fSglass 			if (lines[recno].blen < cnt) {
166d5250e4eSitojun 				if ((n = realloc(lines[recno].l,
167d5250e4eSitojun 				    cnt + 256)) == NULL)
1684917bba2Schristos 					xerr(1, "realloc");
169d5250e4eSitojun 				lines[recno].l = n;
170d5250e4eSitojun 				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)) {
18279059c63Schristos 		free(lines);
183aa97860fSglass 		ierr();
184*2a6f4060Schristos 		return 1;
185ae646d0eSjtc 	}
186aa97860fSglass 	if (cnt) {
187aa97860fSglass 		lines[recno].l = sp;
188aa97860fSglass 		lines[recno].len = cnt;
189aa97860fSglass 		if (++recno == off) {
190aa97860fSglass 			wrap = 1;
191aa97860fSglass 			recno = 0;
192aa97860fSglass 		}
193aa97860fSglass 	}
194aa97860fSglass 
195aa97860fSglass 	if (rflag) {
196aa97860fSglass 		for (cnt = recno - 1; cnt >= 0; --cnt)
197aa97860fSglass 			WR(lines[cnt].l, lines[cnt].len);
198aa97860fSglass 		if (wrap)
199aa97860fSglass 			for (cnt = off - 1; cnt >= recno; --cnt)
200aa97860fSglass 				WR(lines[cnt].l, lines[cnt].len);
201aa97860fSglass 	} else {
202aa97860fSglass 		if (wrap)
203aa97860fSglass 			for (cnt = recno; cnt < off; ++cnt)
204aa97860fSglass 				WR(lines[cnt].l, lines[cnt].len);
205aa97860fSglass 		for (cnt = 0; cnt < recno; ++cnt)
206aa97860fSglass 			WR(lines[cnt].l, lines[cnt].len);
207aa97860fSglass 	}
2087d7dff85Schristos 	free(lines);
209*2a6f4060Schristos 	return 0;
210aa97860fSglass }
211