12061Sjkh/*-
226152Speter * Copyright (c) 1991, 1993
32061Sjkh *	The Regents of the University of California.  All rights reserved.
42061Sjkh *
515603Smarkm * This code is derived from software contributed to Berkeley by
63197Scsgr * Edward Sze-Tyan Wang.
720710Sasami *
820710Sasami * Redistribution and use in source and binary forms, with or without
93197Scsgr * modification, are permitted provided that the following conditions
102061Sjkh * are met:
1112483Speter * 1. Redistributions of source code must retain the above copyright
122160Scsgr *    notice, this list of conditions and the following disclaimer.
132834Swollman * 2. Redistributions in binary form must reproduce the above copyright
142061Sjkh *    notice, this list of conditions and the following disclaimer in the
152061Sjkh *    documentation and/or other materials provided with the distribution.
162160Scsgr * 4. Neither the name of the University nor the names of its contributors
1717308Speter *    may be used to endorse or promote products derived from this software
1819320Sadam *    without specific prior written permission.
1921536Sjmacd *
2025399Sjb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2125980Sasami * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221594Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2317308Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2417308Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2517308Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2617308Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2717308Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2817308Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2917308Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3019175Sbde * SUCH DAMAGE.
3119175Sbde */
3219175Sbde
3319175Sbde#include <sys/cdefs.h>
3417308Speter
3525647Sbde__FBSDID("$FreeBSD: releng/10.3/usr.bin/tail/read.c 245184 2013-01-08 22:14:45Z delphij $");
3617308Speter
372061Sjkh#ifndef lint
382061Sjkhstatic const char sccsid[] = "@(#)read.c	8.1 (Berkeley) 6/6/93";
391594Srgrimes#endif
4025313Sbde
4125313Sbde#include <sys/types.h>
4225313Sbde#include <sys/stat.h>
4325313Sbde
4425313Sbde#include <err.h>
4525313Sbde#include <errno.h>
4625313Sbde#include <fcntl.h>
4725313Sbde#include <stdio.h>
487407Srgrimes#include <stdlib.h>
497108Sphk#include <string.h>
507108Sphk#include <unistd.h>
517108Sphk
527407Srgrimes#include "extern.h"
537407Srgrimes
547407Srgrimes/*
557108Sphk * bytes -- read bytes to an offset from the end and display.
562061Sjkh *
572061Sjkh * This is the function that reads to a byte offset from the end of the input,
582061Sjkh * storing the data in a wrap-around buffer which is then displayed.  If the
5917308Speter * rflag is set, the data is displayed in lines in reverse order, and this
602061Sjkh * routine has the usual nastiness of trying to find the newlines.  Otherwise,
612061Sjkh * it is displayed from the character closest to the beginning of the input to
622061Sjkh * the end.
632061Sjkh */
642061Sjkhint
653197Scsgrbytes(FILE *fp, const char *fn, off_t off)
662626Scsgr{
672626Scsgr	int ch, len, tlen;
682061Sjkh	char *ep, *p, *t;
692061Sjkh	int wrap;
702061Sjkh	char *sp;
712061Sjkh
722061Sjkh	if ((sp = p = malloc(off)) == NULL)
732061Sjkh		err(1, "malloc");
7419320Sadam
752061Sjkh	for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) {
762061Sjkh		*p = ch;
772061Sjkh		if (++p == ep) {
782061Sjkh			wrap = 1;
792061Sjkh			p = sp;
802061Sjkh		}
812061Sjkh	}
822061Sjkh	if (ferror(fp)) {
832061Sjkh		ierr(fn);
842061Sjkh		free(sp);
852061Sjkh		return 1;
862834Swollman	}
872834Swollman
882834Swollman	if (rflag) {
892834Swollman		for (t = p - 1, len = 0; t >= sp; --t, ++len)
902834Swollman			if (*t == '\n' && len) {
912834Swollman				WR(t + 1, len);
921594Srgrimes				len = 0;
934486Sphk		}
944486Sphk		if (wrap) {
954486Sphk			tlen = len;
964486Sphk			for (t = ep - 1, len = 0; t >= p; --t, ++len)
974486Sphk				if (*t == '\n') {
982061Sjkh					if (len) {
992061Sjkh						WR(t + 1, len);
10025979Sjkh						len = 0;
10125979Sjkh					}
10225979Sjkh					if (tlen) {
10325979Sjkh						WR(sp, tlen);
1042061Sjkh						tlen = 0;
10525979Sjkh					}
1062061Sjkh				}
1072061Sjkh			if (len)
10817308Speter				WR(t + 1, len);
1092061Sjkh			if (tlen)
1102061Sjkh				WR(sp, tlen);
1112061Sjkh		}
1122061Sjkh	} else {
1132061Sjkh		if (wrap && (len = ep - p))
11412483Speter			WR(p, len);
11512483Speter		len = p - sp;
11612483Speter		if (len)
11712483Speter			WR(sp, len);
1182061Sjkh	}
1192061Sjkh
1208854Srgrimes	free(sp);
1212061Sjkh	return 0;
1222061Sjkh}
12312483Speter
1242061Sjkh/*
12518714Sache * lines -- read lines to an offset from the end and display.
12618714Sache *
12718714Sache * This is the function that reads to a line offset from the end of the input,
12817308Speter * storing the data in an array of buffers which is then displayed.  If the
12917308Speter * rflag is set, the data is displayed in lines in reverse order, and this
13017308Speter * routine has the usual nastiness of trying to find the newlines.  Otherwise,
13117308Speter * it is displayed from the line closest to the beginning of the input to
13221536Sjmacd * the end.
13315603Smarkm */
13417308Speterint
13517308Speterlines(FILE *fp, const char *fn, off_t off)
13617308Speter{
13717308Speter	struct {
13817308Speter		int blen;
13917308Speter		u_int len;
14017308Speter		char *l;
14117308Speter	} *llines;
14217308Speter	int ch, rc;
14318362Sjkh	char *p, *sp;
14419966Sache	int blen, cnt, recno, wrap;
14518362Sjkh
14617308Speter	if ((llines = calloc(off, sizeof(*llines))) == NULL)
14717308Speter		err(1, "calloc");
14817308Speter	p = sp = NULL;
14917308Speter	blen = cnt = recno = wrap = 0;
15017308Speter	rc = 0;
15117308Speter
15216550Sjkh	while ((ch = getc(fp)) != EOF) {
1532061Sjkh		if (++cnt > blen) {
15417308Speter			if ((sp = realloc(sp, blen += 1024)) == NULL)
1552061Sjkh				err(1, "realloc");
15617308Speter			p = sp + cnt - 1;
1572061Sjkh		}
15817308Speter		*p++ = ch;
15917308Speter		if (ch == '\n') {
16017308Speter			if ((int)llines[recno].blen < cnt) {
16117308Speter				llines[recno].blen = cnt + 256;
16217308Speter				if ((llines[recno].l = realloc(llines[recno].l,
16317308Speter				    llines[recno].blen)) == NULL)
16417466Speter					err(1, "realloc");
16517308Speter			}
16617308Speter			bcopy(sp, llines[recno].l, llines[recno].len = cnt);
16717466Speter			cnt = 0;
16817308Speter			p = sp;
16917308Speter			if (++recno == off) {
17017308Speter				wrap = 1;
17117308Speter				recno = 0;
17217466Speter			}
17317308Speter		}
17417308Speter	}
17517308Speter	if (ferror(fp)) {
17617308Speter		ierr(fn);
17717308Speter		rc = 1;
17817308Speter		goto done;
17917308Speter	}
18017308Speter	if (cnt) {
18117308Speter		llines[recno].l = sp;
18217308Speter		sp = NULL;
18317308Speter		llines[recno].len = cnt;
18417308Speter		if (++recno == off) {
18517308Speter			wrap = 1;
18617308Speter			recno = 0;
18717308Speter		}
18817308Speter	}
18917308Speter
19017308Speter	if (rflag) {
19117308Speter		for (cnt = recno - 1; cnt >= 0; --cnt)
19217308Speter			WR(llines[cnt].l, llines[cnt].len);
19317308Speter		if (wrap)
19417308Speter			for (cnt = off - 1; cnt >= recno; --cnt)
19517308Speter				WR(llines[cnt].l, llines[cnt].len);
19617308Speter	} else {
19717308Speter		if (wrap)
19817308Speter			for (cnt = recno; cnt < off; ++cnt)
19917308Speter				WR(llines[cnt].l, llines[cnt].len);
20018392Speter		for (cnt = 0; cnt < recno; ++cnt)
20117308Speter			WR(llines[cnt].l, llines[cnt].len);
20217308Speter	}
20317308Speterdone:
20417308Speter	for (cnt = 0; cnt < off; cnt++)
20517962Speter		free(llines[cnt].l);
20617308Speter	free(sp);
20717962Speter	free(llines);
20817962Speter	return (rc);
20917962Speter}
21017962Speter