/*----------------------------------------------------------------------*\
 | Program to reverse the order of lines in a text file.				|
 |																		|
 | Usage: reverse input_file											|
 |																		|
 | The output file is named as the input file, with reversed letters.	|
 |																		|
 | Peculiarity: If the last line in the file does not end with CR or LF	|
 | it will be joined with the next-to-last line in the output file.		|
 |																		|
 | Peter N. Schweitzer (U.S. Geological Survey, Reston, VA 22092)		|
\*----------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

/*----------------------------------------------------------------------*\
\*----------------------------------------------------------------------*/

static void strrev (char *s) {
	char *d;
	char c;

	d = s + strlen (s) - 1;
	while (d > s) {
		c = *d;
		*d-- = *s;
		*s++ = c;
		}
	}

static char *data = NULL;
static long data_len = 0;

static void reverse_text (char *input_file) {
	long n,len;
	char output_file[FILENAME_MAX];
	FILE *in, *out;
	char *b,*e,*end;

	if (in = fopen (input_file,"rb")) {
		if (fseek (in,0L,SEEK_END) == 0) {
			len = ftell (in);
			rewind (in);
			if (len > data_len)
				if (!(data = (char *) realloc (data,1+len))) {
					fprintf (stderr,"Error: could not allocate %ld bytes for file %s\n",len,input_file);
					return;
					}
			if ((n = fread (data,1,len,in)) < len) {
				fprintf (stderr,"Error: expected %ld, got %ld bytes from %s\n",len,n,input_file);
				return;
				}

			/*----------------------------------------------------------*\
			 | Compose output file name by reversing input file name.	|
			\*----------------------------------------------------------*/

			strcpy (output_file,input_file);
			strrev (output_file);

			if (!(out = fopen (output_file,"wb"))) {
				fprintf (stderr,"Error: could not create output file %s\n",output_file);
				return;
				}

			/*----------------------------------------------------------*\
			 | Delimit the lines and write them out in reverse order.	|
			\*----------------------------------------------------------*/

			end = data + n;
			b = e = end;
			*end = 0;
			while (e > data) {

				/* Find the beginning of the current line */

				while (b > data) {
					if (*b == '\n') {
						b++;
						break;
						}
					if (*b == '\r') {
						b++;
						break;
						}
					b--;
					}

				/* Write out the line, including the EOL character(s) */

				fwrite (b,1,e-b,out);

				/* Point e at the end of the next line */

				e = b;
				b--;
				if (b > data && *b == '\n') b--;
				if (b > data && *b == '\r') b--;
				}
			fclose (out);
			}
		else {
			fprintf (stderr,"Error: could not seek to end of %s\n",input_file);
			return;
			}
		fclose (in);
		}
	else
		fprintf (stderr,"Warning: could not open input file %s\n",input_file);
	}

main (int argc, char *argv[]) {
	if (argc > 1) reverse_text (argv[1]);
	else {
		fprintf (stderr,"Usage: %s input_file\n",argv[0]);
		exit (0);
		}
	}

/*----------------------------------------------------------------------*\
\*----------------------------------------------------------------------*/

