From: reds@informix.com (Ron Delpiere-Smith)
Newsgroups: comp.databases.informix
Subject: How to read Flat files from 4gl
Date: 18 Apr 1995 02:56:09 GMT

Shankar's Emporium Pte Ltd (shanke11@merlion.singnet.com.sg) wrote:
: I have a requirment to read the flat file from 4GL. Is there any way to 
: do it. 

You would need to use a 'C' routine to read in the file.  I have developed a
these routines in a nice neat little package over the years.  I need to get
these places on the archive server at emory.edu.  Here is a copy of the c
source file,  I also have a man page available.  The code is pretty well
documented.  Right now the headers are in a state of transfer from SCCS 
over to RCS,  sorry about that folks.

Enjoy,
Ron Delpiere-Smith, Informix

P.S. Set you tab stops = 4 (:ts=4) in vi for readability.

------------------------------Cut Here----------------------------
/*
##############################################################################
#	Module			:	file_io.c
#	Description		:	These functions read/write fixed or variable length
#						records from/to files for 4GL
#
#	Functions		:	file_init				Opens a data files.
#						file_close				Closes a data file.
#						file_read				Reads data from a file.
#						file_write				Writes data to a file.
#
#	Revision 		:	$Revision: 1.2 $
#	Author			:	Ron Delpiere-Smith
#	Date			:	%G% %U%
#	Path			:	%P%
#
#	  Date		Author	Comments
#	========	======	=====================================================
#	07/10/89	REDS	Original Coding.
#	09/24/91	REDS	Updated standards, revised documentation.
#	10/02/91	REDS	Defined return codes.
#
##############################################################################
*/

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <memory.h>

#define _FIOMAX		(8)
#define _STAT_OK	(0)		/*	IO status OK.					*/
#define _STAT_ERR	(101)	/*	Gerneral IO Failure				*/
#define _STAT_EOF	(255)	/*	Gerneral IO Failure				*/
#define _INV_PARM	(102)	/*	Invalid number of parameters	*/
#define _INV_FNAM	(103)	/*	Invalid Filename.				*/
#define _INV_FMOD	(104)	/*	Invalid File Mode.				*/
#define _INV_FNUM	(105)	/*	Invalid File Number.			*/
#define _INV_FTYP	(106)	/*	Invalid File Type.				*/
#define _INV_BUF	(107)	/*	Invalid Buffer Length.			*/
#define _NO_FILES	(108)	/*	No files available.				*/
#define _NO_BUF		(109)	/*	No buffer space available.		*/

static struct
{
	char fvflag[2];
	char rwflag[2];
	char *iobuf;
	short ilen;
	short inuse;
	FILE *fp;
} _fio[_FIOMAX];

FILE *fopen();
char *clip();

int ident_file_io()
{
	char *g_sccs_var = "%W%";
	char *g_rcs_var  = "$Header: fgl_fileio.c,v 1.2 95/03/28 13:44:53 rsmith Exp $";
}

/*
##############################################################################
#
#	Description	:	This function will open a unix file in one of 3 modes.
#
#	Usage		:	CALL file_init ( "foo", 256, "r", "f" )
#											RETURNING io_status, file_id
#
#	Logic		:	Open the file and declare the required bufffer space.
#
#	Passed
#	Parameters	:	-	Full pathname of data file to open.
#					-	Size of I/O buffer.
#					-	File I/O Mode Indicator (R/W/A).
#					-	Fixed or Variable length record indicator (F/V).
#
#	Returned
#	Variables	:	-	File I/O Channel Number (smallint).
#					-	File I/O Status (integer).
#
#	  Date		Author	Comments
#	========	======	=====================================================
#	07/10/89	REDS	Original Coding.
#	09/24/91	REDS	Updated standards, revised documentation.
#	10/02/91	REDS	Added usage of DEFINEd return codes.
#
##############################################################################
*/

int file_init( argcount )
int argcount;
{
	int retcode;
	short fidx;

	char flnam[128];

	/*
	*		Check argument count 
	*/

	if ( argcount != 4 )
	{
		retcode = (int) _INV_PARM;
	}
	else
	{
		retcode = 0;
	}


	/*
	*		Set up fio array 
	*/

	if ( retcode == 0 )
	{
		for ( fidx = 0; fidx < _FIOMAX; ++fidx )
		{
			if ( _fio[fidx].inuse == 0 )
			{
				_fio[fidx].inuse = 1;
				break;
			}
		}

		if ( fidx >= _FIOMAX )
		{
			retcode = (int) _NO_FILES;
		}
	}


	if ( retcode == 0 )
	{
		/* 
		*		Get buffer length & filename 
		*/

		(void) memset( _fio[fidx].fvflag, (int) '\0',
											sizeof( _fio[fidx].fvflag ) );

		(void) memset( _fio[fidx].rwflag, (int) '\0',
											sizeof( _fio[fidx].rwflag ) );

		(void) memset( flnam, (int) '\0', sizeof( flnam ) );

		popquote( _fio[fidx].fvflag, 2 );		/*	Fixed/Variable flag	*/
		popquote( _fio[fidx].rwflag, 2 );		/*	Read/Write flag		*/ 
		popshort( &_fio[fidx].ilen );			/*	Length of buffer	*/
		popquote( flnam, sizeof( flnam ) -1 );	/*	Filename			*/
		}

		if ( retcode == 0 )
		{
			/* 
			*		Validate arguments 
			*/

			if ( (int) strlen ( clip ( flnam ) ) <= 1 )
			{
					retcode = (int) _INV_FNAM;
			}
		}

		if ( retcode == 0 )
		{
			if ( _fio[fidx].ilen < 1 )
			{
				retcode = (int) _INV_BUF;
			}
		}

		if ( retcode == 0 )
		{
			_fio[fidx].rwflag[0] = (char) tolower( (int) _fio[fidx].rwflag[0] );

			if	(	_fio[fidx].rwflag[0] != 'r'
				&&	_fio[fidx].rwflag[0] != 'w'
				&&	_fio[fidx].rwflag[0] != 'a' )
			{
				retcode = (int) _INV_FMOD;
			}
		}

		if ( retcode == 0 )
		{
			_fio[fidx].fvflag[0] = (char) tolower( (int) _fio[fidx].fvflag[0] );

			if	(	_fio[fidx].fvflag[0] != 'f'
				&&	_fio[fidx].fvflag[0] != 'v' )
			{
				retcode = (int) _INV_FTYP;
			}
		}


		if ( retcode == 0 )
		{
			/* 
			*		Open the file 
			*/

			if ( (_fio[fidx].fp = fopen( clip( flnam ), _fio[fidx].rwflag ))
								== (FILE *) NULL )
			{
				retcode = (int) _STAT_ERR;
			}
			else
			{
				/* 
				*		Allocate space for the I/O buffer
				*/

				if ( (_fio[fidx].iobuf =
							(char *) malloc( (unsigned) (_fio[fidx].ilen+1) ))
					== (char *) NULL )
				{
					retcode = (int) _NO_BUF;
				}
				else
				{
					retcode = (int) _STAT_OK;
				}
			}
		}

		/* 
		*		Two values are passed back to 4gl 
		*/

		retshort( fidx );
		retint( retcode );

		return( (int) 2 );
}



/*
##############################################################################
#
#	Description	:	This function will allow an Informix-4GL program to 
#					read from a file that was opened for reading using 
#					file_init().
#
#	Usage		:	CALL file_read ( file_id )
#						RETURNING io_status, string
#
#	Logic		:	Open the file and declare the required bufffer space.
#
#	Passed
#	Parameters	:	-	File I/O Channel Number (smallint).
#
#	Returned
#	Variables	:	-	String of data ( char(buf_siz) ).
#					-	File I/O Status (integer).
#
#	  Date		Author	Comments
#	========	======	=====================================================
#	07/10/89	REDS	Original Coding.
#	09/24/91	REDS	Updated standards, revised documentation.
#	10/02/91	REDS	Added usage of DEFINEd return codes.
#
##############################################################################
*/

int file_read( argcount )
int argcount;
{
	short idx;
	int retcode;
	short fidx;

	/* 
	*		Check argument count 
	*/

	if ( argcount != 1 )
	{
		retcode = _INV_PARM;
	}
	else
	{
		retcode = 0;
	}


	if ( retcode == 0 )
	{
		/* 
		*		Get fio index 
		*/

		popshort( &fidx );

		if ( fidx >= _FIOMAX || fidx < 0 )
		{
			retcode = _INV_FNUM;
		}
	}


	if ( retcode == 0 )
	{
		/* 
		*		Initialize the record to Nulls, including null terminator 
		*/

		(void) memset( _fio[fidx].iobuf, (int) '\0', (_fio[fidx].ilen + 1) );


		/* 
		*	Check for end-of-file 
		*/

		if ( feof( _fio[fidx].fp ) )
		{
			retcode = (int) _STAT_EOF;
		}										/* EOF */
		else
		{
			/* 
			*		Read the record as indicated by the flag 
			*/

			if ( _fio[fidx].fvflag[0] == 'f' )
			{
				/* 
				*		Read fixed-length record 
				*/

				if ( fread( _fio[fidx].iobuf, 1, _fio[fidx].ilen,
								_fio[fidx].fp ) == 0 )
				{
					retcode = (int) _STAT_ERR;
				}								/* Read fail */
				else
				{
					retcode = (int) _STAT_OK;
				}								/* Read ok */

			}									/* Read fix. rec. */
			else
			{
				/* 
				*		Read variable-length record 
				*/

				if ( fgets( _fio[fidx].iobuf, _fio[fidx].ilen, _fio[fidx].fp )
											== (char *) NULL )
				{
					retcode = (int) _STAT_ERR;
				}
				else
				{
					retcode = (int) _STAT_OK;
				}

			}									/* Read var. rec. */

		}										/* Not EOF */
	}


	/* 
	*		Two values are passed back to 4gl 
	*/

	retquote( _fio[fidx].iobuf );
	retint( retcode );

	return( (int) 2 );
}


/*
##############################################################################
#
#	Description	:	This function will allow an Informix-4GL program to
#					write to a unix file that was opened in either write 
#					or append modes using file_init()
#
#	Usage		:	CALL file_write ( buffer, file_id )
#						RETURNING io_status
#
#	Logic		:	Open the file and declare the required bufffer space.
#
#	Passed
#	Parameters	:	-	Text buffer to write to file (char).
#					-	File I/O Channel Number (smallint).
#
#	Returned
#	Variables	:	-	File I/O Status (integer).
#
#	  Date		Author	Comments
#	========	======	=====================================================
#	07/10/89	REDS	Original Coding.
#	09/24/91	REDS	Updated standards, revised documentation.
#	10/02/91	REDS	Added usage of DEFINEd return codes.
#
##############################################################################
*/

int file_write( argcount )
int argcount;
{
	int retcode;
	short fidx;

	/* 
	*		Check argument count
	*/

	if ( argcount != 2 )
	{
		retcode = _INV_PARM;
	}
	else
	{
		retcode = 0;
	}


	if ( retcode == 0 )
	{
		/*
		*		Get fio index 
		*/

		popshort( &fidx );

		if ( fidx >= _FIOMAX || fidx < 0 )
		{
			retcode = _INV_FNUM;
		}
	}


	if ( retcode == 0 )
	{
		/*
		*		Initialize the record to Nulls, including null terminator 
		*/

		(void) memset( _fio[fidx].iobuf, (int) '\0', (_fio[fidx].ilen + 1) );

		/*
		*	Get output text
		*/
		popquote( _fio[fidx].iobuf, (_fio[fidx].ilen +1) );

		/*
		*		Check for end-of-file 
		*/

		if ( feof( _fio[fidx].fp ) )
		{
			retcode = (int) _STAT_ERR;
		}												/* EOF */
		else
		{
			/*
			*		Write the record as indicated by the flag
			*/

			if ( _fio[fidx].fvflag[0] == 'f' )
			{
				/*
				*		Write fixed-length record 
				*/

				if ( fwrite( _fio[fidx].iobuf, 1,
							_fio[fidx].ilen, _fio[fidx].fp )
						!= _fio[fidx].ilen )
				{
					retcode = (int) _STAT_ERR;
				}									/* Write fail */
				else
				{
					(void) fflush( _fio[fidx].fp );
					retcode = (int) _STAT_OK;
				}									/* Write ok */
			}										/* Write fix. rec. */
			else
			{
				/*
				*		Write variable-length record 
				*/

				if ( fputs( _fio[fidx].iobuf, _fio[fidx].fp ) == EOF )
				{
					retcode = (int) _STAT_ERR;
				}									/* Write fail */
				else
				{
					/*
					*		Append a newline 
					*/

					if ( fputc( '\n', _fio[fidx].fp ) == EOF )
					{
						retcode = (int) _STAT_ERR;
					}								/* Write fail */
					else
					{
						(void) fflush( _fio[fidx].fp );
						retcode = (int) _STAT_OK;
					}								/* Write ok */
				}									/* Write ok */
			}										/* Write var. rec. */
		}											/* Not EOF */
	}


	/*
	*		One value is passed back to 4gl 
	*/

	retint( retcode );
	return( (int) 1 );
}

/*
##############################################################################
#
#	Description	:	This function will close the indicated file.
#
#	Usage		:	CALL file_close ( file_id )
#						RETURNING io_status
#
#	Passed
#	Parameters	:	-	File I/O Channel Number (smallint).
#
#	Returned
#	Variables	:	-	File I/O Status (integer).
#
#	  Date		Author	Comments
#	========	======	=====================================================
#	07/10/89	REDS	Original Coding.
#	09/24/91	REDS	Updated standards, revised documentation.
#	10/02/91	REDS	Added usage of DEFINEd return codes.
#
##############################################################################
*/

int file_close( argcount )
int argcount;
{
	short fidx;
	int retcode;

	/*	
	*		Check argument count 
	*/

	if ( argcount != 1 )
	{
		retcode = _INV_PARM;
	}
	else
	{
		retcode = 0;
	}

	if ( retcode == 0 )
	{
		/*	
		*		Get fio index 
		*/

		popshort( &fidx );

		if ( fidx >= _FIOMAX || fidx < 0 )
		{
			retcode = _INV_FNUM;
		}
	}

	if ( retcode == 0 )
	{
		/*	
		*		Release the memory 
		*/

		free( _fio[fidx].iobuf );

		/*	
		*		Flush to output buffer 
		*/

		if ( _fio[fidx].rwflag[0] == 'w' )
		{
			(void) fflush( _fio[fidx].fp );
		}


		/*	
		*		Close the file 
		*/

		(void) fclose( _fio[fidx].fp );


		/*	
		*		Release the inuse flag 
		*/

		_fio[fidx].inuse = 0;
	}


	/*
	*		One value is passed back to 4gl 
	*/

	retint( retcode );
	return( (int) 1 );
}

/*
##############################################################################
#
#	Function	:	clip
#
#	Description	:	This function will "clip" a passed Informix character
#					array.	Informix does not terminate strings with a NULL;
#					the strings are left justified, space filled.
#
#	Usage		:	CALL clip ( char_var )
#
#	Logic		:	Loop through Informix character array changing spaces
#					to NULLs.	Spaces are defined as x20x20 or x00x20.
#
#	Module
#	Functions	:	clip
#
#	Called
#	Functions	:	<none>
#
#	Environment
#	Variables	:	<none>
#
#	Referenced
#	Files		:	stdio.h
#					ctype.h
#
#	Log File	:	<none>
#
#	Input Files :	<none>
#
#	Output Files:	<none>
#
#	  Date		Author	Comments
#	========	======	=====================================================
#	07/10/89	REDS	Original Coding.
#	09/24/91	REDS	Update standards, updated documentation.
#
##############################################################################
*/

#include <stdio.h>
#include <ctype.h>

char *clip( pt )
char *pt;
{
	short slen;
	char *ptmp;

	slen = strlen( pt ) - 1;

	if ( slen < 0 )
	{
		return( (char *) NULL );
	}

	ptmp = &pt[slen];

	while( ptmp != pt && isspace( (int) *ptmp ) )
	{
		*(ptmp--) = '\0';
	}

	return( pt );
}
