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' ); } }