File:  [MW Coherent from dump] / coherent / b / STREAMS / conf_79 / input.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * Input stream abstraction.
 */

/*
 *-IMPORTS:
 *	<sys/compat.h>
 *		CONST
 *		USE_PROTO
 *		ARGS ()
 *		LOCAL
 *	<stddef.h>
 *		NULL
 *		offsetof ()
 *	<stdio.h>
 *		EOF
 *		FILE
 *		stderr
 *		fprintf ()
 *		fputs ()
 *		getc ()
 *		putc ()
 *	<stdlib.h>
 *		free ()
 *		malloc ()
 *	<string.h>
 *		memcpy ()
 *		strlen ()
 */

#include <sys/compat.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "lex.h"

#include "input.h"
#include "mkinput.h"


/*
 * Structures for dealing with input from a file.
 */

typedef struct fileinput filein_t;

struct fileinput {
	input_t		fi_input;

	char	      *	fi_name;
	FILE	      *	fi_file;	/* input stream */
	int		fi_lineno;	/* line number in file */
	int		fi_colno;	/* current column number */
	int		fi_prevline;
	int		fi_prevcol;
	int		fi_comment;	/* comment character (maybe none) */
	int		fi_prevchar;	/* previous character */

	char		fi_line [64];	/* line buffer for errors */
};

#define	ARRAY_LEN(a)	(sizeof (a) / sizeof (* a))


/*
 * Structure for processing input from a string.
 */

typedef struct strinput	strin_t;

struct strinput {
	input_t		si_input;

	CONST unsigned char
		      *	si_data;	/* data being read */
	size_t		si_pos;		/* position in input stream */
	size_t		si_len;		/* length of input stream */
};


/*
 * Read a character from a file.
 */

#ifdef	USE_PROTO
LOCAL int fi_read (input_t * input)
#else
LOCAL int
fi_read (input)
input_t	      *	input;
#endif
{
	filein_t      *	fi = (filein_t *) input;
	int		ch;

	/*
	 * Get a character from the input file, recording the data for the
	 * purpose of error reporting.
	 */

	fi->fi_prevcol = fi->fi_colno;
	fi->fi_prevline = fi->fi_lineno;

	if ((ch = getc (fi->fi_file)) == EOF)
		return IN_EOF;

	fi->fi_line [fi->fi_colno ++ % ARRAY_LEN (fi->fi_line)] = ch;

	if (ch == fi->fi_comment) {
		/*
		 * Consume data to EOL, then return EOL.
		 */

		do {
			if ((ch = getc (fi->fi_file)) == EOF)
				return IN_EOF;
		} while (ch != '\n');
	}


	if (ch == '\n') {

		fi->fi_colno = 0;
		fi->fi_lineno ++;
	}

	fi->fi_prevchar = ch;
	return ch;
}


/*
 * Return the last read character to the input stream.
 */

#ifdef	USE_PROTO
LOCAL void fi_unread (input_t * input)
#else
LOCAL void
fi_unread (input)
input_t	      *	input;
#endif
{
	filein_t      *	fi = (filein_t *) input;

	if (fi->fi_prevchar != IN_EOF) {

		ungetc (fi->fi_prevchar, fi->fi_file);

		fi->fi_prevchar = IN_EOF;
		fi->fi_colno = fi->fi_prevcol;
		fi->fi_lineno = fi->fi_prevline;
	}
}


/*
 * Close the input file.
 */

#ifdef	USE_PROTO
LOCAL void fi_close (input_t * input)
#else
LOCAL void
fi_close (input)
input_t	      *	input;
#endif
{
	filein_t      *	fi = (filein_t *) input;

	(void) fclose (fi->fi_file);
	free (fi);
}


/*
 * Produce an error report for this input source.
 */

#ifdef	USE_PROTO
LOCAL void fi_error (input_t * input)
#else
LOCAL void
fi_error (input)
input_t	      *	input;
#endif
{
	filein_t      *	fi = (filein_t *) input;
	int		col;
	int		ch;
	int		end;

	(void) fprintf (stderr, "Error vicinity : file \"%s\", line %d, column %d\n",
			fi->fi_name, fi->fi_prevline, fi->fi_prevcol);

	col = fi->fi_prevcol < 40 ? 0 : fi->fi_prevcol - 40;

	if (fi->fi_colno > (end = fi->fi_prevcol))
		end ++;

	while (col < end) {
		/*
		 * Should think about escaping controls.
		 */

		ch = fi->fi_line [col ++ % ARRAY_LEN (fi->fi_line)];
		(void) putc (ch, stderr);
	}


	fputs (" <---\n", stderr);
}


/*
 * Create a source of input from a file.
 */

#ifdef	USE_PROTO
input_t * (make_file_input) (FILE * file, CONST char * name, int comment)
#else
input_t *
make_file_input ARGS ((file, name, comment))
FILE	      *	file;
CONST char    *	name;
int		comment;
#endif
{
	filein_t      *	fi;
	size_t		namelen;

	/* ASSERT that fi_input is the first member of the structure */

	if (offsetof (filein_t, fi_input) != 0)
		return NULL;

	if (name == NULL)
		name = "no name";

	namelen = strlen (name) + 1;

	if ((fi = (filein_t *) malloc (sizeof (* fi) + namelen)) == NULL)
		return NULL;

	fi->fi_lineno = 1;
	fi->fi_colno = 0;
	fi->fi_file = file;
	fi->fi_name = (char *) (fi + 1);

	fi->fi_comment = comment;
	fi->fi_prevchar = IN_EOF;

	if (namelen > 0)
		memcpy (fi->fi_name, name, namelen);

	fi->fi_input.in_read = fi_read;
	fi->fi_input.in_unread = fi_unread;
	fi->fi_input.in_readtok = NULL;
	fi->fi_input.in_close = fi_close;
	fi->fi_input.in_error = fi_error;

	return & fi->fi_input;
}


/*
 * Return a character from an input string, or EOF when the end-of-string is
 * reached.
 */

#ifdef	USE_PROTO
LOCAL int si_read (input_t * input)
#else
LOCAL int
si_read (input)
input_t	      *	input;
#endif
{
	strin_t	      *	si = (strin_t *) input;

	if (si->si_pos >= si->si_len)
		return IN_EOF;

	return si->si_data [si->si_pos ++];
}


/*
 * Return a character to the input stream to be read again.
 */

#ifdef	USE_PROTO
LOCAL void si_unread (input_t * input)
#else
LOCAL void
si_unread (input)
input_t	      *	input;
#endif
{
	strin_t	      *	si = (strin_t *) input;

	if (si->si_pos > 0)
		si->si_pos --;
}


/*
 * Reading a token, specialized to string input streams.
 */

#ifdef	USE_PROTO
LOCAL CONST unsigned char * si_readtok (input_t * input, lex_t * lexp,
					size_t * lengthp)
#else
LOCAL CONST unsigned char *
si_readtok (input, lexp, lengthp)
input_t	      *	input;
lex_t	      *	lexp;
size_t	      *	lengthp;
#endif
{
	strin_t	      *	si = (strin_t *) input;
	int		start = -1;
	int		ch;

	for (;;) {
		if ((ch = si_read (input)) == IN_EOF)
			break;

		switch (classify (lexp, ch, start == -1)) {

		case CLASS_FLUSH:
			continue;

		case CLASS_SEP:
			si_unread (input);
			goto separator;

		default:
			break;
		}

		if (start == -1)
			start = si->si_pos - 1;
	}

separator:
	* lengthp = start == -1 ? 0 : si->si_pos - start;
	return start == -1 ? NULL : & si->si_data [start];
}


/*
 * Finish with a string input stream.
 */

#ifdef	USE_PROTO
LOCAL void si_close (input_t * input)
#else
LOCAL void
si_close (input)
input_t	      *	input;
#endif
{
	free (input);
}


/*
 * Display an error locus in a string input stream.
 */

#ifdef	USE_PROTO
LOCAL void si_error (input_t * input)
#else
LOCAL void
si_error (input)
input_t	      *	input;
#endif
{
	strin_t       *	si = (strin_t *) input;
	int		col;

	col = si->si_pos < 40 ? 0 : si->si_pos - 40;

	(void) fprintf (stderr, "Error vicinity : %.*s <---\n",
			si->si_pos - col, & si->si_data [col]);
}


/*
 * Create a source of input from a string. Depending on the "action" code,
 * the string may or may not be copied or left alone. If the user wants some
 * clean processing to be done at close time, then another version of this
 * code should be set in place which allows registration of a close-time
 * callback (which is messy, so it hasn't been done).
 */

#ifdef	USE_PROTO
input_t * (make_string_input) (CONST unsigned char * str, int copy)
#else
input_t *
make_string_input ARGS ((str, copy))
CONST unsigned char
	      *	str;
int		copy;
#endif
{
	strin_t	      *	si;
	size_t		len;

	/* ASSERT that si_input is the first member of the structure */

	if (offsetof (strin_t, si_input) != 0)
		return NULL;

	len = strlen ((char *) str);

	if ((si = (strin_t *) malloc (sizeof (* si) +
				      (copy ? len : 0))) == NULL)
		return NULL;

	si->si_pos = 0;
	si->si_len = len;

	if (copy) {

		si->si_data = (CONST unsigned char *) (si + 1);
		memcpy (si + 1, str, len);
	} else
		si->si_data = str;

	si->si_input.in_read = si_read;
	si->si_input.in_unread = si_unread;
	si->si_input.in_readtok = si_readtok;
	si->si_input.in_close = si_close;
	si->si_input.in_error = si_error;

	return & si->si_input;
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.