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