
/********************************************
fin.c

libmawk changes (C) 2009-2012, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:

copyright 1991, 1992.  Michael D. Brennan

This is a source file for mawk, an implementation of
the AWK programming language.

Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
#include "conf.h"
#include <stdlib.h>
#include "mawk.h"
#include "fin.h"
#include "memory.h"
#include "bi_vars.h"
#include "field.h"
#include "symtype.h"
#include "scan.h"
#include "vio.h"
#include <string.h>

#ifndef	  NO_FCNTL_H
#include <fcntl.h>
#endif

/* This file handles input file buffering and (most important) splitting
   files into records, mawk_FINgets().
*/
mawk_input_t *mawk_fin_alloc(mawk_state_t *MAWK, FILE_NODE *parent)
{
	mawk_input_t *fin;

	fin = MAWK_ZMALLOC(MAWK, mawk_input_t);
	fin->flags = MAWK_INPF_START;
	fin->buf = NULL;
	fin->next = NULL;
	fin->used = 0;
	fin->alloced = 0;
	fin->fn = parent;
	return fin;
}


int mawk_is_cmdline_assign(mawk_state_t *, char *);	/* also used by init */

/* frees the buffer, but leaves mawk_input_t structure until
   the user calls close() */
static void mawk_fin_free_buff(mawk_state_t *MAWK, register mawk_input_t *fin)
{
	if (fin->buf != NULL) {
		mawk_zfree(MAWK, fin->buf, fin->alloced);
		fin->buf = NULL; /* marks it semi_closed */
		fin->used = 0;
		fin->alloced = 0;
	}
}

/* user called close() on input file */
void mawk_fin_free(mawk_state_t *MAWK, mawk_input_t *fin)
{
	if (fin->flags & MAWK_INPF_DEAD_NO_FREE)
		return;
	mawk_fin_free_buff(MAWK, fin);
	MAWK_ZFREE(MAWK, fin);
}

/*--------
  Attempt to read size bytes, retry until eof or no_more.
  target is big enough to hold size + 1 chars
  on exit the back of the target is zero terminated, unless error
  Returns the number of bytes read or an error indication if there were no new bytes
  Read exactly size bytes, retrying as needed, unless:
  - eof (first eof: returns the bytes read so far; second call: returns 0)
  - error (first error: return -1, discard the buffer(!))
  - no_more (first no_more: returns the bytes read so far; second no_more: returns no_more)
 *--------------*/
long mawk_fillbuff(mawk_state_t *MAWK, mawk_input_t *fin, register char *target, unsigned size, int interactive)
{
	register int r;
	unsigned entry_size = size;
	{
		while (size) {
			errno = 0;
			fin->flags &= ~MAWK_INPF_NO_MORE;
			switch (r = mawk_vio_read(MAWK, fin->fn->vf, target, size)) {
			case -2:
				fin->flags |= MAWK_INPF_NO_MORE;
				*target = 0;
				if (entry_size - size > 0)
					return entry_size - size;
				return mawk_FIN_nomore;
			case -1:
				{
					int e;
					e = errno;
					mawk_set_errno(MAWK, strerror(e));
					mawk_errmsg(MAWK, e, "read error");
					mawk_exitval(MAWK, 2, -1);
				}
			case 0:
				goto out;

			default:
				target += r;
				size -= r;
				if (interactive)
					goto out;
				break;
			}
		}
	}
out:
	*target = 0;
	return entry_size - size;
}
