version 1.13, 2003/06/03 02:56:17 |
version 1.14, 2003/07/01 11:12:59 |
|
|
static void r_buf(FILE *); |
static void r_buf(FILE *); |
static int r_reg(FILE *, enum STYLE, long, struct stat *); |
static int r_reg(FILE *, enum STYLE, long, struct stat *); |
|
|
|
#define COPYCHAR(fp, ch) \ |
|
do { \ |
|
if ((ch = getc(fp)) == EOF) { \ |
|
ierr(); \ |
|
return (0); \ |
|
} \ |
|
if (putchar(ch) == EOF) { \ |
|
oerr(); \ |
|
return (0); \ |
|
} \ |
|
} while (0) |
|
|
/* |
/* |
* reverse -- display input in reverse order by line. |
* reverse -- display input in reverse order by line. |
* |
* |
|
|
* files by bytes, lines or the whole file. |
* files by bytes, lines or the whole file. |
* |
* |
* BYTES display N bytes |
* BYTES display N bytes |
* REG mmap the file and display the lines |
* REG reverse scan and display the lines |
* NOREG cyclically read characters into a wrap-around buffer |
* NOREG cyclically read characters into a wrap-around buffer |
* |
* |
* LINES display N lines |
* LINES display N lines |
* REG mmap the file and display the lines |
* REG reverse scan and display the lines |
* NOREG cyclically read lines into a wrap-around array of buffers |
* NOREG cyclically read lines into a wrap-around array of buffers |
* |
* |
* FILE display the entire file |
* FILE display the entire file |
* REG mmap the file and display the lines |
* REG reverse scan and display the lines |
* NOREG cyclically read input into a linked list of buffers |
* NOREG cyclically read input into a linked list of buffers |
*/ |
*/ |
void |
void |
|
|
* r_reg -- display a regular file in reverse order by line. |
* r_reg -- display a regular file in reverse order by line. |
*/ |
*/ |
static int |
static int |
r_reg(fp, style, off, sbp) |
r_reg(FILE *fp, enum STYLE style, long off, struct stat *sbp) |
FILE *fp; |
|
enum STYLE style; |
|
long off; |
|
struct stat *sbp; |
|
{ |
{ |
off_t size; |
off_t start, pos, end; |
int llen; |
int ch; |
char *p; |
|
char *start; |
|
|
|
if (!(size = sbp->st_size)) |
end = sbp->st_size; |
|
if (end == 0) |
return (0); |
return (0); |
|
|
if (size > SIZE_T_MAX) |
/* Position before char, ignore last char whether newline or not */ |
return (1); |
pos = end-2; |
|
ch = EOF; |
|
start = 0; |
|
|
if ((start = mmap(NULL, (size_t)size, PROT_READ, MAP_PRIVATE, |
if (style == RBYTES && off < end) |
fileno(fp), (off_t)0)) == MAP_FAILED) |
start = end - off; |
return (1); |
|
p = start + size - 1; |
|
|
|
if (style == RBYTES && off < size) |
for (; pos >= start; pos--) { |
size = off; |
/* A seek per char isn't a problem with a smart stdio */ |
|
if (fseeko(fp, pos, SEEK_SET) != 0) { |
/* Last char is special, ignore whether newline or not. */ |
ierr(); |
for (llen = 1; --size; ++llen) |
return (0); |
if (*--p == '\n') { |
} |
WR(p + 1, llen); |
if ((ch = getc(fp)) == '\n') { |
llen = 0; |
while (--end > pos) |
if (style == RLINES && !--off) { |
COPYCHAR(fp, ch); |
++p; |
end++; |
|
if (style == RLINES && --off == 0) |
break; |
break; |
} |
|
} |
} |
if (llen) |
else if (ch == EOF) { |
WR(p, llen); |
ierr(); |
if (munmap(start, (size_t)sbp->st_size)) |
return (0); |
ierr(); |
} |
|
} |
|
if (pos < start) { |
|
if (ch != EOF && ungetc(ch, fp) == EOF) { |
|
ierr(); |
|
return (0); |
|
} |
|
while (--end >= start) |
|
COPYCHAR(fp, ch); |
|
} |
return (0); |
return (0); |
} |
} |
|
|