Annotation of src/usr.bin/tail/read.c, Revision 1.20
1.20 ! martijn 1: /* $OpenBSD: read.c,v 1.19 2017/02/01 20:21:19 tb Exp $ */
1.1 deraadt 2: /* $NetBSD: read.c,v 1.4 1994/11/23 07:42:07 jtc Exp $ */
3:
4: /*-
5: * Copyright (c) 1991, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Edward Sze-Tyan Wang.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
1.7 millert 19: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #include <sys/types.h>
37: #include <sys/stat.h>
1.3 millert 38:
39: #include <err.h>
1.1 deraadt 40: #include <stdio.h>
1.15 millert 41: #include <stdint.h>
1.1 deraadt 42: #include <stdlib.h>
43: #include <string.h>
1.3 millert 44: #include <unistd.h>
45:
1.1 deraadt 46: #include "extern.h"
47:
48: /*
49: * bytes -- read bytes to an offset from the end and display.
50: *
51: * This is the function that reads to a byte offset from the end of the input,
52: * storing the data in a wrap-around buffer which is then displayed. If the
53: * rflag is set, the data is displayed in lines in reverse order, and this
54: * routine has the usual nastiness of trying to find the newlines. Otherwise,
55: * it is displayed from the character closest to the beginning of the input to
56: * the end.
1.4 ericj 57: *
1.5 mpech 58: * A non-zero return means an (non-fatal) error occurred.
1.4 ericj 59: *
1.1 deraadt 60: */
1.4 ericj 61: int
1.17 tedu 62: bytes(struct tailfile *tf, off_t off)
1.1 deraadt 63: {
1.8 kjell 64: int ch;
65: size_t len, tlen;
1.6 mpech 66: char *ep, *p, *t;
1.1 deraadt 67: int wrap;
68: char *sp;
69:
1.15 millert 70: if (off > SIZE_MAX)
1.8 kjell 71: errx(1, "offset too large");
72:
1.1 deraadt 73: if ((sp = p = malloc(off)) == NULL)
1.3 millert 74: err(1, NULL);
1.1 deraadt 75:
1.17 tedu 76: for (wrap = 0, ep = p + off; (ch = getc(tf->fp)) != EOF;) {
1.1 deraadt 77: *p = ch;
78: if (++p == ep) {
79: wrap = 1;
80: p = sp;
81: }
82: }
1.17 tedu 83: if (ferror(tf->fp)) {
84: ierr(tf->fname);
1.10 otto 85: free(sp);
1.4 ericj 86: return(1);
1.1 deraadt 87: }
88:
89: if (rflag) {
90: for (t = p - 1, len = 0; t >= sp; --t, ++len)
91: if (*t == '\n' && len) {
92: WR(t + 1, len);
93: len = 0;
1.16 tobias 94: }
1.1 deraadt 95: if (wrap) {
96: tlen = len;
97: for (t = ep - 1, len = 0; t >= p; --t, ++len)
98: if (*t == '\n') {
99: if (len) {
100: WR(t + 1, len);
101: len = 0;
102: }
103: if (tlen) {
104: WR(sp, tlen);
105: tlen = 0;
106: }
107: }
108: if (len)
109: WR(t + 1, len);
110: if (tlen)
111: WR(sp, tlen);
112: }
113: } else {
114: if (wrap && (len = ep - p))
115: WR(p, len);
1.3 millert 116: if ((len = p - sp))
1.1 deraadt 117: WR(sp, len);
118: }
1.10 otto 119:
120: free(sp);
1.4 ericj 121: return(0);
1.1 deraadt 122: }
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.
1.4 ericj 133: *
1.5 mpech 134: * A non-zero return means an (non-fatal) error occurred.
1.4 ericj 135: *
1.1 deraadt 136: */
1.4 ericj 137: int
1.17 tedu 138: lines(struct tailfile *tf, off_t off)
1.1 deraadt 139: {
140: struct {
1.8 kjell 141: size_t blen;
142: size_t len;
1.1 deraadt 143: char *l;
1.18 martijn 144: } *lines = NULL;
1.11 otto 145: int ch, rc = 0;
1.6 mpech 146: char *p = NULL;
1.8 kjell 147: int wrap;
1.18 martijn 148: size_t cnt, lineno, nlineno, recno, blen, newsize;
1.8 kjell 149: char *sp = NULL, *newp = NULL;
150:
1.15 millert 151: if (off > SIZE_MAX)
1.8 kjell 152: errx(1, "offset too large");
1.1 deraadt 153:
1.18 martijn 154: lineno = blen = cnt = recno = wrap = 0;
1.1 deraadt 155:
1.17 tedu 156: while ((ch = getc(tf->fp)) != EOF) {
1.1 deraadt 157: if (++cnt > blen) {
1.8 kjell 158: newsize = blen + 1024;
159: if ((newp = realloc(sp, newsize)) == NULL)
1.3 millert 160: err(1, NULL);
1.8 kjell 161: sp = newp;
162: blen = newsize;
1.1 deraadt 163: p = sp + cnt - 1;
164: }
165: *p++ = ch;
1.18 martijn 166: if (recno >= lineno) {
167: nlineno = (lineno + 1024) > off ?
168: (size_t) off : lineno + 1024;
1.20 ! martijn 169: if ((lines = recallocarray(lines, lineno, nlineno,
! 170: sizeof(*lines))) == NULL)
1.18 martijn 171: err(1, NULL);
172: lineno = nlineno;
173: }
1.1 deraadt 174: if (ch == '\n') {
175: if (lines[recno].blen < cnt) {
1.8 kjell 176: newsize = cnt + 256;
177: if ((newp = realloc(lines[recno].l,
178: newsize)) == NULL)
1.3 millert 179: err(1, NULL);
1.8 kjell 180: lines[recno].l = newp;
181: lines[recno].blen = newsize;
1.1 deraadt 182: }
1.3 millert 183: memcpy(lines[recno].l, sp, (lines[recno].len = cnt));
1.1 deraadt 184: cnt = 0;
185: p = sp;
186: if (++recno == off) {
187: wrap = 1;
188: recno = 0;
189: }
190: }
191: }
1.17 tedu 192: if (ferror(tf->fp)) {
193: ierr(tf->fname);
1.11 otto 194: rc = 1;
195: goto done;
1.1 deraadt 196: }
197: if (cnt) {
198: lines[recno].l = sp;
199: lines[recno].len = cnt;
1.13 otto 200: sp = NULL;
1.1 deraadt 201: if (++recno == off) {
202: wrap = 1;
203: recno = 0;
204: }
205: }
206:
207: if (rflag) {
1.8 kjell 208: for (cnt = recno; cnt > 0; --cnt)
209: WR(lines[cnt - 1].l, lines[cnt - 1].len);
1.1 deraadt 210: if (wrap)
1.8 kjell 211: for (cnt = off; cnt > recno; --cnt)
212: WR(lines[cnt - 1].l, lines[cnt - 1].len);
1.1 deraadt 213: } else {
214: if (wrap)
215: for (cnt = recno; cnt < off; ++cnt)
216: WR(lines[cnt].l, lines[cnt].len);
217: for (cnt = 0; cnt < recno; ++cnt)
218: WR(lines[cnt].l, lines[cnt].len);
219: }
1.11 otto 220: done:
1.18 martijn 221: for (cnt = 0; cnt < lineno; cnt++)
1.11 otto 222: free(lines[cnt].l);
223: free(sp);
224: free(lines);
225: return(rc);
1.1 deraadt 226: }