#include <stdio.h>
#include <ibase.h>
#include "example.h"

#ifndef CHAR
#define CHAR        unsigned char
#endif

#ifndef SHORT
#define SHORT       unsigned short
#endif

static void set_statistics PROTO((char*, ISC_BLOB_CTL));
static int read_text PROTO((SHORT, ISC_BLOB_CTL));
static int dump_text PROTO((SHORT, ISC_BLOB_CTL));
static int caller PROTO((SHORT, ISC_BLOB_CTL, SHORT, CHAR*, SHORT*));

#define	ACTION_open 0
#define	ACTION_get_segment 1
#define	ACTION_close 2
#define	ACTION_put_segment 3
#define	ACTION_create 4

#define SUCCESS			0
#define FAILURE			1

#define BUFFER_LENGTH		512

#ifdef SHLIB_DEFS
#define system		(*_libfun_system)
#define fopen		(*_libfun_fopen)
#define unlink		(*_libfun_unlink)
#define fprintf		(*_libfun_fprintf)
#define fclose		(*_libfun_fclose)
#define fgetc		(*_libfun_fgetc)

extern int	system();
extern FILE	*fopen();
extern int	unlink();
extern int	fprintf();
extern int	fclose();
extern int	fgetc();
#endif

static char prevbuf[BUFFER_LENGTH + 1];
static int width = 40;

int EXPORT desc_filter (ARG(SHORT, action), ARG(ISC_BLOB_CTL, control))
ARGLIST(SHORT action)
ARGLIST(ISC_BLOB_CTL control)
{
/**************************************
 *
 *	d e s c _  f i l t e r 
 *
 **************************************
 *
 * Functional description
 *	Format a blob into 40-character-wide
 *  paragraphs.
 *  Read the blob into a file and process
 *	it on open, then read it back line by
 *	line in the get_segment loop.
 *
 **************************************/
int	status;
FILE	*text_file;
char	*out_buffer;

switch (action)
    {
	case ACTION_open:
		prevbuf[0] = '\0';
		if (status = dump_text (action, control))
			return status;
		set_statistics("desc.txt", control);  /* set up stats in ctl struct */
		break;

	case ACTION_get_segment:
		/* open the file first time through and save the file pointer */
		if (!control->ctl_data [0])
		{
			text_file = fopen ("desc.txt", "r");
			control->ctl_data[0] = (long) text_file;
		}
		if (status = read_text (action, control))
			return status;
		break;

	case ACTION_close:
		/* don't need the temp files any more, so clean them up */
		/*unlink("desc.txt");*/
		break;

	case ACTION_create:
	case ACTION_put_segment:
		return isc_uns_ext;
    }

	return SUCCESS;
}

static int caller (ARG(SHORT, action), ARG(ISC_BLOB_CTL, control),
                   ARG(SHORT, buffer_length), ARG(CHAR*, buffer),
                   ARG(SHORT*, return_length))
ARGLIST(SHORT action)
ARGLIST(ISC_BLOB_CTL control)
ARGLIST(SHORT buffer_length)
ARGLIST(CHAR *buffer)
ARGLIST(SHORT *return_length)
{
/**************************************
 *
 *        c a l l e r
 *
 **************************************
 *
 * Functional description
 *        Call next source filter.  This 
 *        is a useful service routine for
 *        all blob filters.
 *
 **************************************/
int        status;
ISC_BLOB_CTL        source;

source = control->ctl_source_handle;
source->ctl_status = control->ctl_status;
source->ctl_buffer = buffer;
source->ctl_buffer_length = buffer_length;

status = (*source->ctl_source) (action, source);

if (return_length)
    *return_length = source->ctl_segment_length;

return status;
}


static int dump_text (ARG(SHORT, action), ARG(ISC_BLOB_CTL, control))
ARGLIST(SHORT action)
ARGLIST(ISC_BLOB_CTL control)
{
/**************************************
 *
 *	d u m p _ t e x t 
 *
 **************************************
 *
 * Functional description
 *	Open a blob and write the
 *	contents to a file
 *
 **************************************/
	FILE	*text_file;
	CHAR	buffer [BUFFER_LENGTH + 1];
	SHORT	length;
	int		status;
	int		i, j;
	CHAR	tbuf [BUFFER_LENGTH + 1];

 
	if (!(text_file = fopen ("desc.txt", "w")))
		return FAILURE;

	while (!(status = caller (ACTION_get_segment, control, sizeof(buffer) - 1,
		buffer, &length)))
    {
		buffer[length] = 0; 
		sprintf(tbuf, "%s%s", prevbuf, buffer);

		length = strlen(tbuf);

		/* replace any new-lines with space */
        for (i = 0; i < length; i++) {
            if (tbuf[i] == '\n')    
                tbuf[i] = ' '; 
        } 
 
		i = 0;
		/* break the line up into width-length pieces */
		for (; i < length; i++)
		{
			/* save the remainder */
            if (strlen(&tbuf[i]) <= 40) {
                sprintf(prevbuf, "%s ", &tbuf[i]);
                break;
            }
 
			/* find end-of-word to break the line at */
            for (j = width - 1; j >= 0; j--) {
                if (isspace(tbuf[i + j]))
                    break;
            }
            if (j < 0)
                j = width;
            fprintf (text_file, "%*.*s\n", j, j, &tbuf[i]);
 
            i = i + j;
		}
    }
	/* print the remainder */
	fprintf(text_file, "%s\n", prevbuf);

	fclose (text_file);

	if (status != isc_segstr_eof)
		return status;

	return SUCCESS;
}

static void set_statistics (ARG(char*, filename), ARG(ISC_BLOB_CTL, control))
ARGLIST(char filename)
ARGLIST(ISC_BLOB_CTL control)
{
/*************************************
 *
 *	s e t _ s t a t i s t i c s
 *
 *************************************
 *
 * Functional description
 *	Sets up the statistical fields
 *	in the passed in ctl structure.
 *	These fields are:
 *	  ctl_max_segment - length of
 *	     longest seg in blob (in
 *	     bytes)
 *	  ctl_number_segments - # of
 *	     segments in blob
 *	  ctl_total_length - total length
 *	     of blob in bytes.
 *	we should reset the
 *	ctl structure, so that 
 *	blob_info calls get the right
 *	values.
 *
 *************************************/
register int	max_seg_length;
register int	length;
register int	num_segs;
register int	cur_length;
FILE		*file;
char		*p;
char		c;

num_segs = 0;
length = 0;
max_seg_length = 0;
cur_length = 0;

file = fopen ("desc.txt", "r");

while (1)
    {
    c = fgetc (file);
    if (feof (file))
	break;
    length++;
    cur_length++;

    if (c == '\n')    /* that means we are at end of seg */
	{
	if (cur_length > max_seg_length)
	    max_seg_length = cur_length;
	num_segs++;
	cur_length = 0;
	}
    }

control->ctl_max_segment = max_seg_length;
control->ctl_number_segments = num_segs;
control->ctl_total_length = length;
}

static int read_text (ARG(SHORT, action), ARG(ISC_BLOB_CTL, control))
ARGLIST(SHORT action)
ARGLIST(ISC_BLOB_CTL control)
{
/**************************************
 *
 *	r e a d _ t e x t 
 *
 **************************************
 *
 * Functional description
 *	Reads a file one line at a time 
 *	and puts the data out as if it 
 *	were coming from a blob. 
 *
 **************************************/
CHAR	*p;
FILE	*file;
SHORT	length;
int	c, status;


p = control->ctl_buffer;
length = control->ctl_buffer_length;
file = (FILE *)control->ctl_data [0];

for (;;)
{
	c = fgetc (file);
	if (feof (file))
		break;
	*p++ = c;
	if ((c == '\n')  || p >= control->ctl_buffer + length)
	{
		control->ctl_segment_length = p - control->ctl_buffer; 
		if (c == '\n')
			return SUCCESS; 
		else
			return isc_segment;
	}
}

return isc_segstr_eof;
}
