static char sccsid
[] = "@(#)tac.c 1.1 %G%";
* tac.c - Print file segments in reverse order
* Original line-only version by unknown author off the net.
* 1985 mods by Jay Lepreau, Univ of Utah, to allocate memory dynamically
* and handle string bounded segments.
* This should be defined for BSD releases later than 4.2 and for Sys V.2,
* at least. fwrite is faster than putc only if you have a new speedy fwrite.
#ifdef DEBUG /* dbx can't handle registers */
/* Default target string and bound */
int right
= 1; /* right or left bounded segments? */
int readsize
= 4096; /* significantly faster than 1024 */
extern char *malloc(), *realloc();
register char *p
, *pastend
;
register int firstchar
, targm1len
; /* target length minus 1 */
(void) fprintf(stderr
, "Usage: tac [-string | +string] file ...\n");
readsize
= atoi(argv
[1]);
if (argv
[1][0] == '+' || argv
[1][0] == '-') {
right
= (argv
[1][0] == '+');
bufsize
= (readsize
<< 1) + targlen
+ 2;
if ((buf
= malloc((unsigned) bufsize
)) == NULL
) {
perror("tac: initial malloc");
(void) strcpy(buf
, targ
); /* stop string at beginning */
if (stat(p
= *++argv
, &st
) < 0) {
if ((off
= st
.st_size
) == 0)
if ((fd
= open(p
, 0)) < 0) {
* Arrange for the first read to lop off enough to
* leave the rest of the file a multiple of readsize.
* Since readsize can change, this may not always hold during
* the pgm run, but since it usually will, leave it here
* for i/o efficiency (page/sector boundaries and all that).
* Note: Above statement has never been verified!
if ((i
= off
% readsize
) == 0)
(void) lseek(fd
, off
, 0);
if (read(fd
, buf
, i
) != i
) {
p
= pastend
= buf
+ i
; /* pastend always points to end+1 */
while ( *--p
!= firstchar
||
(targm1len
&& strncmp(p
+1, targ
+1, targm1len
)) )
if (p
< buf
) { /* backed off front of buffer */
/* beginning of file: dump last segment */
output(p
+ targlen
, pastend
);
if ((i
= pastend
- buf
) > readsize
) {
int newbufsize
= (readsize
<< 2) + targlen
+ 2;
if ((tbuf
= realloc(buf
-targlen
, (unsigned) newbufsize
)) == NULL
) {
/* If realloc fails, old buf contents may be lost. */
perror("tac: segment too long; may have garbage here");
tbuf
+= targlen
; /* skip over the stop string */
readsize
= readsize
<< 1;
/* guaranteed to fit now (I think!) */
if (off
- readsize
< 0) {
(void) lseek(fd
, off
, 0); /* back up */
/* Shift pending old data right to make room for new */
bcopy(buf
, p
= buf
+ readsize
, i
);
if (read(fd
, buf
, readsize
) != readsize
) {
/* Found a real instance of the target string */
output(right
? p
+ targlen
: p
, pastend
);
* Dump chars from p to pastend-1. If right-bounded by target
* and not the first time through, append the target string.
(void) fwrite(p
, 1, pastend
- p
, stdout
);
(void) putc(*p
++, stdout
);
(void) fwrite(targ
, 1, targlen
, stdout
);
perror("tac: fwrite/putc");
exit(++numerr
> 1 ? numerr
: 1);
fprintf(stderr
, "tac: ");