Text Fragment Extractor

TkTkorrovi 0 Tallied Votes 127 Views Share

Text fragment extractor (usage: fragment /pattern/[n] [/pattern/[n]] file), similar to the print command in ed and vi, with pattern range. If the second pattern is omitted, prints to the end of file. Use quotation marks when there are spaces in the argument. Finds the first pattern, then the second pattern, then calculates the range, so considering that make sure that the range is correct.

/*
** fragment.c -- text fragment, public domain by tkorrovi@mail.com
** Usage: fragment /pattern/[n] [/pattern/[n]] file
** Similar to print command in ed and vi, with pattern range
** If the second pattern is omitted, prints to the end of file
** Use quotation marks when there are spaces in the argument
** Finds the first pattern, then second pattern, then calculates the
** range, so considering that make sure that the range is correct
*/

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

FILE *file;
char line [FILENAME_MAX], pattern [FILENAME_MAX], *last;

char *gs (char *s, int n, FILE *stream)
{
	char *output;

	output = fgets (s, n, stream);
	if (ferror (stream)) exit (1);
	return output;
}

int ps (const char *s, FILE *stream)
{
	int output;

	output = fputs (s, stream);
	if (ferror (stream)) exit (1);
	return output;
}

long findline (char *argument, long *i, int start)
{
	long n = 0;

	if (strlen (argument) < 2) exit (1);
	strcpy (pattern, argument + 1);
	if (strrchr (pattern, '/') == NULL) exit (1);
	n = atoi (strrchr (pattern, '/') + 1);
	*strrchr (pattern, '/') = 0;
	for (*i = start; 
		(last = gs (line, sizeof line, file)) != NULL; 
		(*i)++)
	{
		if (strstr (line, pattern) != NULL 
			|| !strcmp (pattern, ""))
		{
			break;
		}
	}
	if (last == NULL) exit (1);
	return n;
}

int main (int argc, char *argv [])
{
	long l1 = 0, l2 = 0, n1, n2, i;

	if (argc < 3 || argc > 4) return 1;
	if ((file = fopen (argv [argc - 1], "r")) == 0) return 1;
	n1 = findline (argv [1], &l1, 1);
	if (argc > 3) n2 = findline (argv [2], &l2, l1 + 1);
	if (l2 + n2 < l1 + n1 || l1 + n1 < 1 
		|| l2 + n2 < 1)
	{
		return 1;
	}
	if (fseek (file, 0, SEEK_SET)) return 1;
	if (l1 + n1 > 1)
	{
		for (i = 1; i < l1 + n1; i++)
		{
			last = gs (line, sizeof line, file);
		}
	}
 	if (last == NULL) return 1;	
	if (argc == 3)
	{
		while (gs (line, sizeof line, file) != NULL)
		{
			ps (line, stdout);
		}
	}
	else
	{
		for (i = l1 + n1; i <= l2 + n2; i++)
		{
			last = gs (line, sizeof line, file);
			if (last == NULL) break;
			ps (line, stdout);
		}
	}
	return 0;
}