1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Edward Sze-Tyan Wang. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)read.c 5.4 (Berkeley) 06/16/92"; 13 #endif /* not lint */ 14 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 #include <fcntl.h> 18 #include <errno.h> 19 #include <unistd.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include "extern.h" 24 25 /* 26 * bytes -- read bytes to an offset from the end and display. 27 * 28 * This is the function that reads to a byte offset from the end of the input, 29 * storing the data in a wrap-around buffer which is then displayed. If the 30 * rflag is set, the data is displayed in lines in reverse order, and this 31 * routine has the usual nastiness of trying to find the newlines. Otherwise, 32 * it is displayed from the character closest to the beginning of the input to 33 * the end. 34 */ 35 void 36 bytes(fp, off) 37 register FILE *fp; 38 off_t off; 39 { 40 register int ch, len, tlen; 41 register char *ep, *p, *t; 42 int wrap; 43 char *sp; 44 45 if ((sp = p = malloc(off)) == NULL) 46 err(1, "%s", strerror(errno)); 47 48 for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) { 49 *p = ch; 50 if (++p == ep) { 51 wrap = 1; 52 p = sp; 53 } 54 } 55 if (ferror(fp)) { 56 ierr(); 57 return; 58 } 59 60 if (rflag) { 61 for (t = p - 1, len = 0; t >= sp; --t, ++len) 62 if (*t == '\n' && len) { 63 WR(t + 1, len); 64 len = 0; 65 } 66 if (wrap) { 67 tlen = len; 68 for (t = ep - 1, len = 0; t >= p; --t, ++len) 69 if (*t == '\n') { 70 if (len) { 71 WR(t + 1, len); 72 len = 0; 73 } 74 if (tlen) { 75 WR(sp, tlen); 76 tlen = 0; 77 } 78 } 79 if (len) 80 WR(t + 1, len); 81 if (tlen) 82 WR(sp, tlen); 83 } 84 } else { 85 if (wrap && (len = ep - p)) 86 WR(p, len); 87 if (len = p - sp) 88 WR(sp, len); 89 } 90 } 91 92 /* 93 * lines -- read lines to an offset from the end and display. 94 * 95 * This is the function that reads to a line offset from the end of the input, 96 * storing the data in an array of buffers which is then displayed. If the 97 * rflag is set, the data is displayed in lines in reverse order, and this 98 * routine has the usual nastiness of trying to find the newlines. Otherwise, 99 * it is displayed from the line closest to the beginning of the input to 100 * the end. 101 */ 102 void 103 lines(fp, off) 104 register FILE *fp; 105 off_t off; 106 { 107 struct { 108 u_int blen; 109 u_int len; 110 char *l; 111 } *lines; 112 register int ch; 113 register char *p; 114 int blen, cnt, recno, wrap; 115 char *sp; 116 117 if ((lines = malloc(off * sizeof(*lines))) == NULL) 118 err(1, "%s", strerror(errno)); 119 120 sp = NULL; 121 blen = cnt = recno = wrap = 0; 122 123 while ((ch = getc(fp)) != EOF) { 124 if (++cnt > blen) { 125 if ((sp = realloc(sp, blen += 1024)) == NULL) 126 err(1, "%s", strerror(errno)); 127 p = sp + cnt - 1; 128 } 129 *p++ = ch; 130 if (ch == '\n') { 131 if (lines[recno].blen < cnt) { 132 lines[recno].blen = cnt + 256; 133 if ((lines[recno].l = realloc(lines[recno].l, 134 lines[recno].blen)) == NULL) 135 err(1, "%s", strerror(errno)); 136 } 137 bcopy(sp, lines[recno].l, lines[recno].len = cnt); 138 cnt = 0; 139 p = sp; 140 if (++recno == off) { 141 wrap = 1; 142 recno = 0; 143 } 144 } 145 } 146 if (ferror(fp)) { 147 ierr(); 148 return; 149 } 150 if (cnt) { 151 lines[recno].l = sp; 152 lines[recno].len = cnt; 153 if (++recno == off) { 154 wrap = 1; 155 recno = 0; 156 } 157 } 158 159 if (rflag) { 160 for (cnt = recno - 1; cnt >= 0; --cnt) 161 WR(lines[cnt].l, lines[cnt].len); 162 if (wrap) 163 for (cnt = off - 1; cnt >= recno; --cnt) 164 WR(lines[cnt].l, lines[cnt].len); 165 } else { 166 if (wrap) 167 for (cnt = recno; cnt < off; ++cnt) 168 WR(lines[cnt].l, lines[cnt].len); 169 for (cnt = 0; cnt < recno; ++cnt) 170 WR(lines[cnt].l, lines[cnt].len); 171 } 172 } 173