reverse.c (313100) | reverse.c (314427) |
---|---|
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Edward Sze-Tyan Wang. 7 * 8 * Redistribution and use in source and binary forms, with or without --- 23 unchanged lines hidden (view full) --- 32 33#if 0 34#ifndef lint 35static char sccsid[] = "@(#)reverse.c 8.1 (Berkeley) 6/6/93"; 36#endif /* not lint */ 37#endif 38 39#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Edward Sze-Tyan Wang. 7 * 8 * Redistribution and use in source and binary forms, with or without --- 23 unchanged lines hidden (view full) --- 32 33#if 0 34#ifndef lint 35static char sccsid[] = "@(#)reverse.c 8.1 (Berkeley) 6/6/93"; 36#endif /* not lint */ 37#endif 38 39#include <sys/cdefs.h> |
40__FBSDID("$FreeBSD: stable/11/usr.bin/tail/reverse.c 313100 2017-02-02 18:27:20Z asomers $"); | 40__FBSDID("$FreeBSD: stable/11/usr.bin/tail/reverse.c 314427 2017-02-28 22:49:41Z asomers $"); |
41 42#include <sys/param.h> | 41 42#include <sys/param.h> |
43#include <sys/queue.h> |
|
43#include <sys/stat.h> 44#include <sys/mman.h> 45 46#include <err.h> 47#include <errno.h> 48#include <limits.h> 49#include <stdint.h> 50#include <stdio.h> --- 113 unchanged lines hidden (view full) --- 164 if (curoff < 0 && mapprint(&map, 0, lineend) != 0) { 165 ierr(fn); 166 return; 167 } 168 if (map.start != NULL && munmap(map.start, map.maplen)) 169 ierr(fn); 170} 171 | 44#include <sys/stat.h> 45#include <sys/mman.h> 46 47#include <err.h> 48#include <errno.h> 49#include <limits.h> 50#include <stdint.h> 51#include <stdio.h> --- 113 unchanged lines hidden (view full) --- 165 if (curoff < 0 && mapprint(&map, 0, lineend) != 0) { 166 ierr(fn); 167 return; 168 } 169 if (map.start != NULL && munmap(map.start, map.maplen)) 170 ierr(fn); 171} 172 |
172typedef struct bf { 173 struct bf *next; 174 struct bf *prev; 175 int len; 176 char *l; 177} BF; | 173#define BSZ (128 * 1024) 174typedef struct bfelem { 175 TAILQ_ENTRY(bfelem) entries; 176 size_t len; 177 char l[BSZ]; 178} bfelem_t; |
178 179/* 180 * r_buf -- display a non-regular file in reverse order by line. 181 * 182 * This is the function that saves the entire input, storing the data in a 183 * doubly linked list of buffers and then displays them in reverse order. 184 * It has the usual nastiness of trying to find the newlines, as there's no 185 * guarantee that a newline occurs anywhere in the file, let alone in any 186 * particular buffer. If we run out of memory, input is discarded (and the 187 * user warned). 188 */ 189static void 190r_buf(FILE *fp, const char *fn) 191{ | 179 180/* 181 * r_buf -- display a non-regular file in reverse order by line. 182 * 183 * This is the function that saves the entire input, storing the data in a 184 * doubly linked list of buffers and then displays them in reverse order. 185 * It has the usual nastiness of trying to find the newlines, as there's no 186 * guarantee that a newline occurs anywhere in the file, let alone in any 187 * particular buffer. If we run out of memory, input is discarded (and the 188 * user warned). 189 */ 190static void 191r_buf(FILE *fp, const char *fn) 192{ |
192 BF *mark, *tl, *tr; 193 int ch, len, llen; | 193 struct bfelem *tl, *first = NULL; 194 size_t llen; |
194 char *p; | 195 char *p; |
195 off_t enomem; | 196 off_t enomem = 0; 197 TAILQ_HEAD(bfhead, bfelem) head; |
196 | 198 |
197 tl = NULL; 198#define BSZ (128 * 1024) 199 for (mark = NULL, enomem = 0;;) { | 199 TAILQ_INIT(&head); 200 201 while (!feof(fp)) { 202 size_t len; 203 |
200 /* 201 * Allocate a new block and link it into place in a doubly 202 * linked list. If out of memory, toss the LRU block and 203 * keep going. 204 */ | 204 /* 205 * Allocate a new block and link it into place in a doubly 206 * linked list. If out of memory, toss the LRU block and 207 * keep going. 208 */ |
205 if (enomem || (tl = malloc(sizeof(BF))) == NULL || 206 (tl->l = malloc(BSZ)) == NULL) { 207 if (!mark) | 209 while ((tl = malloc(sizeof(bfelem_t))) == NULL) { 210 first = TAILQ_FIRST(&head); 211 if (TAILQ_EMPTY(&head)) |
208 err(1, "malloc"); | 212 err(1, "malloc"); |
209 if (enomem) 210 tl = tl->next; 211 else { 212 if (tl) 213 free(tl); 214 tl = mark; 215 } 216 enomem += tl->len; 217 } else if (mark) { 218 tl->next = mark; 219 tl->prev = mark->prev; 220 mark->prev->next = tl; 221 mark->prev = tl; 222 } else { 223 mark = tl; 224 mark->next = mark->prev = mark; | 213 enomem += first->len; 214 TAILQ_REMOVE(&head, first, entries); 215 free(first); |
225 } | 216 } |
217 TAILQ_INSERT_TAIL(&head, tl, entries); |
|
226 227 /* Fill the block with input data. */ | 218 219 /* Fill the block with input data. */ |
228 for (p = tl->l, len = 0; 229 len < BSZ && (ch = getc(fp)) != EOF; ++len) 230 *p++ = ch; 231 232 if (ferror(fp)) { 233 ierr(fn); 234 return; | 220 len = 0; 221 while ((!feof(fp)) && len < BSZ) { 222 p = tl->l + len; 223 len += fread(p, 1, BSZ - len, fp); 224 if (ferror(fp)) { 225 ierr(fn); 226 return; 227 } |
235 } 236 | 228 } 229 |
237 /* 238 * If no input data for this block and we tossed some data, 239 * recover it. 240 */ 241 if (!len && enomem) { 242 enomem -= tl->len; 243 tl = tl->prev; 244 break; 245 } 246 | |
247 tl->len = len; | 230 tl->len = len; |
248 if (ch == EOF) 249 break; | |
250 } 251 252 if (enomem) { 253 warnx("warning: %jd bytes discarded", (intmax_t)enomem); 254 rval = 1; 255 } 256 257 /* | 231 } 232 233 if (enomem) { 234 warnx("warning: %jd bytes discarded", (intmax_t)enomem); 235 rval = 1; 236 } 237 238 /* |
258 * Step through the blocks in the reverse order read. The last char 259 * is special, ignore whether newline or not. | 239 * Now print the lines in reverse order 240 * Outline: 241 * Scan backward for "\n", 242 * print forward to the end of the buffers 243 * free any buffers that start after the "\n" just found 244 * Loop |
260 */ | 245 */ |
261 for (mark = tl;;) { 262 for (p = tl->l + (len = tl->len) - 1, llen = 0; len--; 263 --p, ++llen) 264 if (*p == '\n') { 265 if (llen) { | 246 tl = TAILQ_LAST(&head, bfhead); 247 first = TAILQ_FIRST(&head); 248 while (tl != NULL) { 249 struct bfelem *temp; 250 251 for (p = tl->l + tl->len - 1, llen = 0; p >= tl->l; 252 --p, ++llen) { 253 int start = (tl == first && p == tl->l); 254 255 if ((*p == '\n') || start) { 256 struct bfelem *tr; 257 258 if (start && llen) 259 WR(p, llen + 1); 260 else if (llen) |
266 WR(p + 1, llen); | 261 WR(p + 1, llen); |
267 llen = 0; | 262 tr = TAILQ_NEXT(tl, entries); 263 llen = 0; 264 if (tr != NULL) { 265 TAILQ_FOREACH_FROM_SAFE(tr, &head, 266 entries, temp) { 267 if (tr->len) 268 WR(&tr->l, tr->len); 269 TAILQ_REMOVE(&head, tr, 270 entries); 271 free(tr); 272 } |
268 } | 273 } |
269 if (tl == mark) 270 continue; 271 for (tr = tl->next; tr->len; tr = tr->next) { 272 WR(tr->l, tr->len); 273 tr->len = 0; 274 if (tr == mark) 275 break; 276 } | |
277 } | 274 } |
275 } |
|
278 tl->len = llen; | 276 tl->len = llen; |
279 if ((tl = tl->prev) == mark) 280 break; | 277 tl = TAILQ_PREV(tl, bfhead, entries); |
281 } | 278 } |
282 tl = tl->next; 283 if (tl->len) { 284 WR(tl->l, tl->len); 285 tl->len = 0; 286 } 287 while ((tl = tl->next)->len) { 288 WR(tl->l, tl->len); 289 tl->len = 0; 290 } | 279 TAILQ_REMOVE(&head, first, entries); 280 free(first); |
291} | 281} |