/*	Convert floating field formatted data files to fixed field

    <taskname> <input filename> [<output filename>]

    <taskname> - Determined at task-build/install time (Try FFF).
    <input filename> - The ASCII data file to be reformatted.
    <output filename> - The file to receive the reformatted ASCII data.
    	The default is to use the same name as the input file.

The input file is assumed to contain records of ASCII data in floating format
(i.e. variable length) fields. Each field is delimited by one or more
white_space characters.

Note: Null fields delimited by a comma are not ignored.
For example, in the record:

    "123, , 456, 789"

The first field contains "123", the second field contains "", the third field
contains "456", and the fourth field contains "789". Each field must be
"occupied" by at least one data character and/or a comma.

Input records with fewer fields than the maximum number of fields per record
found in the file will have blank (space-filled) fields appended to the
output record. Thus all output records will be the same length.

*/

#include	<std.h>
#include	<stdio.h>
#include	<qioret.h>

#define	MAX_CHARACTERS	1000
TEXT		record[MAX_CHARACTERS];
INTEGER		field[MAX_CHARACTERS >> 1];
INTEGER		fields = 0;
GLOBAL STRING	white_space;


LOCAL STRING
start_field (end)
STRING	end;
{
/*
It is assumed that "end" is pointing to the end of the previous field
(i.e. the first delimiter after field data characters), and we want to
find the start of the next field's data characters (i.e. skip over delimiters).

If the end-of-field is delimited by a comma, move the end pointer to the next
character in the string before skipping white_space. The white_space characters
do not include the comma.
*/
if (*end == ',')
    end++;
white_space = " \t";
return (skip_white (end));
}

LOCAL STRING
end_field (start)
STRING	start;
{
/*
It is assumed that "start" is pointing to the start of the previous field
(i.e. the first data character of the field), and we want to find the end
of the field's data characters (i.e. the first delimiter after the data
characters; skip non-white_space characters).

The delimiters include the comma.
*/
white_space = " \t,";
return (skip_n_white (start));
}


main (count, argument)
INTEGER	count;
STRING	argument[];
{
REGISTER STRING	start;
REGISTER STRING	end;
REGISTER	amount;
INTEGER		number;
FILE		*input;
FILE		*output;


/*
Get the input filename (start) and output filename (end).
*/
if (count == 1)
    {
    if (!(printf ("Input file: "), gets (start = &record)) || !strlen (start))
	exit ();
    if (!(printf ("Output file: "), gets (end = &record[MAX_CHARACTERS >> 1])))
	exit ();
    else if (!strlen (end))
	end = start;
    }
else
    {
    start = argument[1];
    if (count > 2)
	end = argument[2];
    else
	end = start;
    }
/*
Open the input and output files.
*/
if (! (input = fopen (start, "r")))
    {
    printf ("Unable to open input file %s\n%s\n", start, ioerrmsg (IO_ERROR));
    exit ();
    }
if (! (output = fopen (end, "w")))
    {
    printf ("Unable to open output file %s\n%s\n", end, ioerrmsg (IO_ERROR));
    exit ();
    }

/*
Scan each record of the input file.
*/
while (fgetss (record, MAX_CHARACTERS, input))
    {
    /*
    Measure the length of each field in the record, and keep a running
    maximum length value for each sequential field in a record, and the
    maximum number of fields in all records.
    */
    for (
	count = 0, start = start_field (record), end = end_field (start);
	*start;
	count++, start = start_field (end), end = end_field (start)
	)
	if (field[count] < (amount = end - start))
	    field[count] = amount;
    if (fields < count)
	fields = count;
    }

if (fields)
    {
    /*
    List the output record format.
    */
    printf ("\n%d fields per record -\n  1(@  1): %3d\n", fields, field[0]);
    for (
	count = 1, number = field[0] + 1;
	count < fields;
	number += field[count++]
	)
	printf ("%3d(@%3d): %3d\n", count + 1, number, ++field[count]);
    printf ("%d characters per record.\n", --number);

    rewind (input);

    /*
    Reformat all file records.
    */
    for (number = 0; fgetss (record, MAX_CHARACTERS, input); number++)
	{
	for (
	    count = 0, start = start_field (record), end = end_field (start);
	    *start;
	    count++, start = start_field (end), end = end_field (start)
	    )
	    {
	    if (*start == ',')
		{
		*start = ' ';
		amount = 1;
		}
	    else
		amount = end - start;
	    fprintf (output, "%*.*s", field[count], amount, start);
	    }
	for (;count < fields; count++)
	    fprintf (output, "%*s", field[count], " ");
	fprintf (output, "\n");
	}

    printf ("%d records output.\n", number);
    }
else
    printf ("No data fields!\n");

fclose (input);
fclose (output);
}
