/*

page 0.1.1, 2003-06-25
Written by Christian Stigen Larsen <csl@sublevel3.org>

Synopsis:
	Prints pages from standard input or a file.  See the manual.

*/

#include <stdlib.h>
#include <stdio.h>

typedef struct options_ {
	long pageno;
	long linespp;
	bool showlineno;
	bool printfromstart;
	bool printtoend;
} options;

options defaultoptions = {1, 25, false, false, false};

void help() {
	printf("page 0.1.1 2003-06-24\n\
Written by Christian Stigen Larsen <csl@sublevel3.org>\n\
\n\
Copyright (C) 2003 Christian Stigen Larsen.\n\
This is free software; see the source for copying conditions.  There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
\n\
Usage: page [OPTION(s)] [FILE(s)]\n\
Prints a page from standard input or file(s).\n\
\n\
Options:\n\
   -h         Print help\n\
   -N or -pN  Print only page N, where 1 is the first page\n\
   +N         Print page N and onwards\n\
   -lN        Use N lines per page\n\
   -s         Print line numbers\n\
   -i         Print from start, up to and including page N\n\
\n\
Examples:\n\
   Print lines 26-50 to output:\n\
      seq 50 | page -2\n\
\n\
   Print page 2 in 10 lines-per-page from all .txt-files:\n\
      page -2 -l10 *.txt\n\
\n");

}

int readfile(FILE* file, const options& params) {

	char buf[1024];

	long pos(1),
	  start( (params.pageno-1) * params.linespp),
	  end(start + params.linespp);

	while ( fgets(buf, sizeof buf, file) != NULL ) {

		if ( pos > start || params.printfromstart ) {
			if ( pos > end && !params.printtoend ) return 0;
			if ( params.showlineno ) printf("%ld: ", pos);
			printf("%s", buf);
		}

		++pos;
	}

	return 0;
}

char* trim(char* s) { // remove spaces
	while ( *s == ' ' ) ++s;
	return s;
}

void storeopt(char* s, options& params, const char prefix) {
	switch ( *s ) {
	case 'h':
		help();
		exit(0);
		break;

	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		if ( prefix == '+' ) params.printtoend = true;
		--s;
	case 'p':
		params.pageno = atol(trim(s+1));
		if ( params.pageno < 1 ) params.pageno = 1;
		break;

	case 'i':
		params.printfromstart = true;
		break;

	case 'l':
		params.linespp = atol(trim(s+1));
		if ( params.linespp < 1 ) params.linespp = 1;
		break;

	case 's':
		params.showlineno = true;
		break;

	default:
		printf("Unknown option: -%c\n\n", *s);
		help();
		exit(1);
		break;
	}
}

void readopts(char* argv[], int argc, options& params) {
	for ( int n(1); n<argc; ++n ) {
		if ( *argv[n] == '-' || *argv[n] == '+' )
			storeopt(argv[n]+1, params, *argv[n]);
	}
}

int readfiles(char* argv[], int argc, options& params) {

	int filesread(0);

	for ( int n(1); n<argc; ++n )
		if ( *argv[n]!='-' && *argv[n]!='+' ) {

			++filesread;

			FILE* f = fopen(argv[n], "rb");

			if ( f ) {
				readfile(f, params);
				fclose(f);
			} else {
				fprintf(stderr, "Error opening file for reading: %s\n", argv[n]);
				exit(1);
			}
		}

	return filesread;
}


int main(int argc, char* argv[]) {
	options params = defaultoptions;

	readopts(argv, argc, params);

	if ( readfiles(argv, argc, params) == 0 )
		return readfile(stdin, params);

	return 0;
}
