[net.sources] A program to list files from bottom to top

stephen@dcl-cs.UUCP (Stephen J. Muir) (08/31/85)

Here is a program which reverses the order of lines in files.
----------------------------------- cut here ----------------------------------
#!/bin/sh
echo 'Start of pack.out, part 01 of 01:'
echo 'x - revfile.1'
sed 's/^X//' > revfile.1 << '/'
X.TH REVERSE 1  "30 August 1985"
X.SH NAME
Xrevfile \- reverse order of lines in files
X.SH SYNOPSIS
X.B revfile
X[ file ] ...
X.SH DESCRIPTION
X.I Revfile
Xcopies the named files to the standard output, reversing the order of the lines.
XIf no file is specified, the standard input is copied.
XThe filename \*(lq-\*(rq also refers to the standard input.
XLines can be arbitrary length.
X.SH BUGS
XThe effect is irreversible if the last character of the file isn't '\\n',
Xobviously.
X.SH AUTHOR
XStephen J. Muir (dcl-cs!stephen)
/
echo 'x - revfile.c'
sed 's/^X//' > revfile.c << '/'
X/* Written by Stephen J. Muir, Computing Dept., Lancaster University
X * stephen@uk.ac.lancs.comp
X * stephen@uk.ac.lancaster.computing
X * dcl-cs!stephen
X *
X * revfile(1) - reverse order of lines in files
X *
X */
X
X# include <stdio.h>
X# include <sys/types.h>
X# include <sys/stat.h>
X# include <sys/file.h>
X
X# define BUFSIZE	4096
X
Xextern char	*malloc ();
X
Xchar	*standin = "-", *tmpfile = "/tmp/revfileXXXXXX";
X
Xstruct stat	mystat;
X
Xstruct list
X	{ char		l_buf [BUFSIZE];
X	  short		l_cnt;
X	  struct list	*l_next;
X	}	*head, *pool;
X
X/* insert data at beginning of list */
Xlinsert (buf, size)
X	char	*buf;
X	{ register struct list	*lp;
X	  if (size == 0)
X		return;
X	  if (lp = pool)	/* try to reuse a list element */
X		pool = pool->l_next;
X	  else if ((lp = (struct list *)malloc (sizeof (struct list))) == 0)
X	  { fprintf (stderr, "Out of memory\n");
X	    exit (1);
X	  }
X	  bcopy (buf, lp->l_buf, size);
X	  lp->l_cnt = size;
X	  lp->l_next = head;
X	  head = lp;	/* insert at head of list */
X	}
X
Xlflush (buf, size)
X	char	*buf;
X	{ register struct list	*lp;
X	  if (size && fwrite (buf, 1, size, stdout) != size)
X	  { perror ("stdout");
X	    exit (1);
X	  }
X	  while (head)		/* flush list */
X	  { if (fwrite (head->l_buf, 1, head->l_cnt, stdout) != head->l_cnt)
X	    { perror ("stdout");
X	      exit (1);
X	    }
X	    head = (lp = head)->l_next;
X	    lp->l_next = pool;
X	    pool = lp;		/* add to list of old elements */
X	  }
X	}
X
Xrevfile (name)
X	char	*name;
X	{ static char	buf [BUFSIZE];
X	  register char	*cp, *ep;
X	  register int	ofd, nfd, i, pos, newpos;
X	  if (strcmp (name, standin))	/* open the file */
X	  { if ((ofd = open (name, O_RDONLY)) == -1)
X	    { perror (name);
X	      return (1);
X	    }
X	  }
X	  else
X		ofd = 0;
X	  /* attempt to use original file */
X	  if (fstat (ofd, &mystat) == -1 ||
X	      (mystat.st_mode & S_IFMT) != S_IFREG ||	/* regular file? */
X	      (pos = lseek (ofd, 0, L_XTND)) == -1	/* go to EOF? */
X	     )
X	  { pos = 0;				/* failed - copy file */
X	    if ((nfd = open (tmpfile, O_RDWR|O_CREAT, 0)) == -1 ||
X		unlink (tmpfile) == -1
X	       )
X	    { perror (tmpfile);
X	      goto erroro;
X	    }
X	    while ((i = read (ofd, buf, BUFSIZE)) > 0)
X	    { if (write (nfd, buf, i) != i)
X	      { perror (tmpfile);
X		goto errorn;
X	      }
X	      pos += i;
X	    }
X	    if (i == -1)
X	    { perror (name);
X	      goto errorn;
X	    }
X	    close (ofd);
X	    ofd = nfd;
X	    name = tmpfile;
X	  }
X	  while (pos)
X	  { if ((newpos = pos - BUFSIZE) < 0)
X		newpos = 0;
X	    i = pos - newpos;
X	    if (lseek (ofd, newpos, L_SET) != newpos || read (ofd, buf, i) != i)
X	    { perror (name);
X	      goto erroro;
X	    }
X	    for (cp = ep = &buf [i]; cp > &buf [0]; )
X		if (*--cp == '\n')
X		{ lflush (cp + 1, ep - (cp + 1));
X		  ep = cp + 1;
X		}
X	    linsert (cp, ep - cp);
X	    pos = newpos;
X	  }
X	  lflush (0, 0);
X	  if (ofd)
X		close (ofd);
X	  return (0);
Xerrorn:	  close (nfd);
Xerroro:	  if (ofd)
X		close (ofd);
X	  return (1);
X	}
X
X/*ARGSUSED*/
Xmain (argc, argv, envp)
X	char	*argv [], *envp [];
X	{ register short	exitstat = 0;
X	  if (--argc <= 0)
X	  { argv = &standin;
X	    argc = 1;
X	  }
X	  else
X		++argv;
X	  mktemp (tmpfile);
X	  while (argc--)
X		if (revfile (*argv++))
X			exitstat = 1;
X	  if (fclose (stdout) == EOF)
X	  { perror ("stdout");
X	    exit (1);
X	  }
X	  exit (exitstat);
X	}
/
echo 'Part 01 of pack.out complete.'
exit
-- 
UUCP:	...!seismo!mcvax!ukc!dcl-cs!stephen
DARPA:	stephen%lancs.comp@ucl-cs	| Post: University of Lancaster,
JANET:	stephen@uk.ac.lancs.comp	|	Department of Computing,
Phone:	+44 524 65201 Ext. 4599		|	Bailrigg, Lancaster, UK.
Project:Alvey ECLIPSE Distribution	|	LA1 4YR

stephen@dcl-cs.UUCP (Stephen J. Muir) (09/04/85)

In article <419@dcl-cs.UUCP> stephen@dcl-cs.UUCP (Stephen J. Muir) writes:
>Here is a program which reverses the order of lines in files.

Actually, it seems people may not realise how useful this program is.  It's
invaluable for scanning the news/uucp history file backwards, for example.

It does NOT need to read the whole file first so it's extremely fast.
-- 
UUCP:	...!seismo!mcvax!ukc!dcl-cs!stephen
DARPA:	stephen%lancs.comp@ucl-cs	| Post: University of Lancaster,
JANET:	stephen@uk.ac.lancs.comp	|	Department of Computing,
Phone:	+44 524 65201 Ext. 4599		|	Bailrigg, Lancaster, UK.
Project:Alvey ECLIPSE Distribution	|	LA1 4YR

brf@link.UUCP (Bruce Fowler) (09/06/85)

$ cat spoon >/dev/bug	# Gag on that, line eater!

	O.K ... I CAN'T STAND IT ANYMORE ... ALL THAT CREATIVITY!

	Here is the *ultimate* way to invert the lines in a file:
		
		$ tip <filename> | tip

	Enjoy!
						Bruce Fowler
^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v^v
    "The Twilight Zone - Love it or Leave it..."

 ____  ==> [ unzip here ]
|____)-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-
/* tip.c - tip section of text sideways (90 degrees counterclockwise) */

#include	<stdio.h>
#define	TXTSIDE	80	/* number of rows and columns maximum */
int incval;		/* column increment, 1 or 2 */
int padflag;		/* to keep leading blank lines */

main(argc, argv )
int argc;
char *argv[];
{
	char *p;	/* for flag arg analysis */
	int nrfiles;	/* how many files processed */
	FILE *fp;	/* files to process */

	/* analyze flags and do each file argument */
	incval = 1;
	padflag = 0;
	nrfiles = 0;
	while (--argc > 0 ) {   /* process each argument */
		p = *++argv;
		if (*p == '-' ) {	/* suck up flags */
			while (*++p != '\0' ) switch (*p ) {
			/* s and d are opposite */
			case 'd':	/* pretend input is double spaced */
				incval = 2;
				break;
			case 's':	/* stop double spacing */
				incval = 1;
				break;
			/* p and n are opposite */
			case 'p':	/* keep padding at left (top) */
				padflag = 1;
				break;
			case 'n':	/* left justify output */
				padflag = 0;
				break;
			default:
				fputs("usage: tip [-dspn] [<file>] ...\n",
					stderr );
				exit(1 );
			}
		} else {
			nrfiles++;	/* file name provided */
			if ((fp = fopen(*argv,"r" )) == NULL ) {
				 fputs("tip: can't open ", stderr );
				 fputs(*argv, stderr );
				 putc('\n', stderr );
			} else {
				tip(fp ); /* process new file */
				fclose(fp );
			}
		}
	}
	if (nrfiles == 0 ) {  /* no file args -- process std input */
		tip(stdin);
	}
}

tip(input )		/* writes to stdout - truncates and pads as necessary */
	FILE *input;
{
	char pix[TXTSIDE][TXTSIDE];
	int len[TXTSIDE];	/* size of useful data in each line */
	int i,j;		/* row and column, what else? */
	int c;		/* as in Current Character */
	int jinc;		/* row increment */

	/* initialize array of linesizes */
	for (i=0; i<TXTSIDE; i++ ) len[i] = -1;
	/* set text array to blanks */
	memset(pix, ' ', TXTSIDE*TXTSIDE );
	/* read input, spread chars down left edge */
	c = ' ';
	jinc = (padflag) ? incval : 0;
	for (j=0; j<TXTSIDE && c!=EOF; j+=jinc ) {
		/* get a character to chew on */
		c = getc(input );
		for (i=0; i<TXTSIDE && c!='\n' && c!=EOF; i++ ) {
			if (c > ' ' && c <= '~' ) {
				pix[i][j] = c;
				if (len[i]<j ) len[i] = j;
				jinc = incval;
			}
			/* adjust row position to next tab stop */
			else if (c == '\t' ) i += 8 - (i + 9 ) & 07;
			c = getc(input );
		}
		/* throw away end of long lines */
		while (c!='\n' && c!=EOF ) c = getc(input );
	}
	/* trim off trailing blank lines */
	for (i=0; i<TXTSIDE && len[i]==(-1); i++ ) len[i] = (-2);
	/* trim off leading blank lines */
	for (i=TXTSIDE-1; i>=0 && len[i]<0; i-- );
	/* print out the result */
	for ( ; i>=0 && len[i]!=(-2); i-- ) {
		for (j=0; j<=len[i]; j++ ) putchar(pix[i][j] );
		putchar('\n' );
	}
}