
/*
**  $VER: personal_pbm_io.c 5.0 (20.02.96)
**
**  C source for personal_pbm_io.library.
**  SAS/C source code.
**
**  Copyright © 1996 Cloanto Italia srl
**	    All Rights Reserved
*/

#include <exec/types.h>
#include <libraries/personal_io.h>
#include <string.h>

/*
 *  pragma aliases
 */
#define SysBase picinfo->SysBase
#define DOSBase picinfo->DOSBase
#define GfxBase picinfo->GfxBase
#define IntuitionBase picinfo->IntuitionBase
#define IconBase picinfo->IconBase

static UBYTE VersionStr[] = "$VER:Personal PBM IO Library 5.0 (20.02.96)";

/*
 *  The PBM library just supports one picture type
 */
#define DATA_PBM  0
#define DATA_NUM  1

static struct DataInfoEntry DInfo[DATA_NUM] =
{
   {
	DATA_PBM,	/* PBM picture type code */
	DIF_LOAD	/* attr: planar images images can be loaded */
	| DIF_LOAD_24	/* attr: 24bit chunky images can be loaded */
	| DIF_SAVE	/* attr: planar images can be saved
	                   (converted to 24bit PBM data, if required) */
	| DIF_LOADFILE	/* attr: the data is read from file */
	| DIF_SAVEFILE	/* attr: the data is written to file */
	| DIF_RECOGNIZE /* attr: PBM files can be recognized */
	| DIF_SAVEOPTS, /* attr: there are options for WritePicture() */
	PCDT_FORMAT	/* data: image format */
	| PCDT_IMAGE    /* data: image bitmap */
	| PCDT_PALETTE, /* data: color palette (PBM/PGM images) */
	450,		/* sort priority */
	"PBM",		/* full name */
	"PBM",		/* short name */
	{ ".pbm", ".pgm", ".ppm" }	/* file name suffixes */
   }
};
static LONG DataCount;	/* counter used by query functions */

/*
 *  PBM Options
 *
 *  AUTO: if 0, 24-bit data is always saved,
 *        if 1, based on the image being saved,
 *        B/W or gray-level or 24bit data is saved.
 *
 *  BINARY: if 0, ASCII PBM files are saved
 *          if 1, binary PBM files are saved.
 */
#define PBM_OPT_AUTO    0
#define PBM_OPT_BINARY  1
#define PBM_OPTIONS_NUM 2

static struct DataOptionEntry PbmOptions[PBM_OPTIONS_NUM] =
{
   {
	DOT_BOOL,	/* Type */
	"AUTO",		/* Name */
	DOUI_AUTO,	/* UITextStr */
	0,		/* Flags: WritePicture() option */
	1,		/* Value */
	0, 1, 1,	/* Min, Max, Default */
	""	},	/* String */
   {
	DOT_BOOL,	/* Type */
	"BINARY",	/* Name */
	DOUI_BINARY,	/* UITextStr */
	0,		/* Flags: WritePicture() option */
	1,		/* Value */
	0, 1, 1,	/* Min, Max, Default */
	""	}	/* String */
};

/* data used by the option query functions */

static struct DataOptionEntry *Options[DATA_NUM] = { PbmOptions };
static LONG DataOptionMax[DATA_NUM] = { PBM_OPTIONS_NUM-1 };
static LONG DataOptionCount[DATA_NUM];

/*
 *  library interface protos
 */
__asm BOOL __saveds GetFirstDataInfo(register __a0 struct DataInfo *);
__asm BOOL __saveds GetNextDataInfo(register __a0 struct DataInfo *);
__asm WORD __saveds GetPictureInfo(register __a0 struct PictureInfo *);
__asm LONG __saveds GetProgressBumps(register __a0 struct PictureInfo *);
__asm WORD __saveds ReadPicture(register __a0 struct PictureInfo *);
__asm WORD __saveds WritePicture(register __a0 struct PictureInfo *);
__asm void __saveds IOLibCleanup(register __a0 struct PictureInfo *);
__asm BOOL __saveds GetFirstOption(register __a0 struct DataInfo *, register __a1  struct DataOption *);
__asm BOOL __saveds GetNextOption(register __a0 struct DataInfo *, register __a1  struct DataOption *);
__asm void __saveds SetOption(register __a0 struct DataInfo *, register __a1  struct DataOption *);
__asm void __saveds ResetOptions(register __a0 struct DataInfo *);
__asm WORD __saveds PersonalIOPrivate1(void);
__asm WORD __saveds PersonalIOPrivate2(void);
__asm WORD __saveds PersonalIOPrivate3(void);

/*
 *  library's standard static protos
 */
static void GetDataInfo(struct DataInfo *, LONG);
static void GetDataOption(struct DataOption *, struct DataOptionEntry *);
static BOOL Handshake(struct DataInfo *);

/*
 *  PBM-specific protos
 */
static int GetFileNum(struct PictureInfo *);
static UBYTE *SkipBlank(UBYTE *);
static BOOL WriteFileNum(int, struct PictureInfo *);

/*
 *  PBM subtypes
 */
#define PBM_ASCII  0  /* "P1" - portable bitmap (B/W, ASCII) */
#define PGM_ASCII  1  /* "P2" - portable graymap (gray levels, ASCII) */
#define PPM_ASCII  2  /* "P3" - portable pixmap (24 bit, ASCII) */
#define PBM_BINARY 3  /* "P4" - portable bitmap (B/W, binary) */
#define PGM_BINARY 4  /* "P5" - portable graymap (gray levels, binary) */
#define PPM_BINARY 5  /* "P6" - portable pixmap (24 bit, binary) */
#define NO_FORMAT  -1








/*
 *  Standard query dispatcher:
 *  the n'th DataInfoEntry is copied to 'dinfo'.
 *
 *  This function does not usually need to be changed,
 *  unless the library supports run-time defined picture types.
 */
static void GetDataInfo(struct DataInfo *dinfo, LONG n)
{
	struct DataInfoEntry *de = &DInfo[n];
	LONG s;

	dinfo->Code = de->Code;
	dinfo->Flags = de->Flags;
	dinfo->ProcessData = de->ProcessData;
	dinfo->Priority = de->Priority;
	strcpy(dinfo->Name, de->Name);
	strcpy(dinfo->ShortName, de->ShortName);

	for (s = 3; --s >= 0; )
	{
		if (de->FileSuffix[s])
			strcpy(&dinfo->FileSuffix[s][0], de->FileSuffix[s]);
		else
			dinfo->FileSuffix[s][0] = 0;
	}
	memset(dinfo->pad, 0, sizeof(dinfo->pad));
}

/*
 *  Standard handshake function:
 *  FALSE is returned if handshaking fails,
 *  TRUE if it succeeds.
 */
static BOOL Handshake(struct DataInfo *dinfo)
{
	/*
	 * Cloanto is a registered trademark of Cloanto Italia srl;
	 * use of the following handshaking protocol requires a license,
	 * which is normally available at no charge for non-commercial use.
         */
	static UBYTE hs_text[] = "Cloanto®";

	if (dinfo->Version >= 5)  /* V5 of client interface feature */
	{
		if (dinfo->HandshakeText == NULL)
			return(FALSE);
		if (strcmp(dinfo->HandshakeText, hs_text) != 0)
			return(FALSE);
		/*
		 * the library internal string is passed
		 */
		dinfo->HandshakeText = hs_text;
	}
	return(TRUE);
}

/*
 *  Standard query function
 *  (support for multiple picture types is included)
 */
__asm BOOL __saveds GetFirstDataInfo(register __a0 struct DataInfo *dinfo)
{
	if (Handshake(dinfo))
	{
		DataCount = 0;
		if (DataCount < DATA_NUM)
		{
			GetDataInfo(dinfo, DataCount++);
			return(TRUE);
		}
	}
	return(FALSE);
}

/*
 *  Standard query function
 *  (support for multiple picture types is included)
 */
__asm BOOL __saveds GetNextDataInfo(register __a0 struct DataInfo *dinfo)
{
	if (Handshake(dinfo))
	{
		if (DataCount < DATA_NUM)
		{
			GetDataInfo(dinfo, DataCount++);
			return(TRUE);
		}
	}
	return(FALSE);
}

/*
 *  This function skips comments and blank characters
 */
static UBYTE *SkipBlank(UBYTE *ptr)
{
	for (; *ptr == ' '  ||
	       *ptr == '\t' ||
	       *ptr == '\n' ||
	       *ptr == '\r' ||
	       *ptr == '#' ;  ptr++)
	{
		if (*ptr == '#')  /* skip comment */
		{
			for (ptr++; *ptr != '\n' && *ptr != '\r' && *ptr != 0; ptr++) ;
		}
	}
	return(ptr);
}

/*
 *  File recognition function:
 *  when the file has been successfully identified,
 *  the image format must be returned.
 */
__asm WORD __saveds GetPictureInfo(register __a0 struct PictureInfo *picinfo)
{
	UBYTE *fh, *fh2;
	WORD format, n;
	int val;

	if (picinfo->Version < 3)
		return(PIOERR_BADVER);
	/*
	 *  picinfo->Data.Code is ignored: the PBM library just supports
	 *  one picture type.
	 *  Multiple type libraries must check the type code:
	 *  if it is DIC_ANYDATA, any library's type is OK,
	 *  otherwise just the specified picture type can be loaded.
	 */

	fh = picinfo->FileHead;
	fh2 = fh + 1;

	if (*fh == 'P' && *fh2 >= '1' && *fh2 <= '6')
		format = *fh2 - '1';	/* OK: it is a valid PBM file */
	else
		return(PIOERR_BADTYPE);	/* not a PBM file */

	GetDataInfo(&picinfo->Data, DATA_PBM);	/* give full information about this picture type */

	fh = SkipBlank(fh+2);
	if ((n = stcd_i(fh, &val)) == 0)  /* get image width */
		return(PIOERR_BADTYPE);
	picinfo->Width = val;

	fh = SkipBlank(fh + n);
	if ((n = stcd_i(fh, &val)) == 0)  /* get image height */
		return(PIOERR_BADTYPE);
	picinfo->Height = val;

	if (format != PBM_ASCII && format != PBM_BINARY)
	{
		fh = SkipBlank(fh + n);
		if ((n = stcd_i(fh, &val)) == 0)  /* get maximum color-component value */
			return(PIOERR_BADTYPE);
		if (val == 0)
			return(PIOERR_BADTYPE);
		picinfo->User1 = (APTR)val;	/* it will be used later */
	}
	fh += n;
	fh2 = SkipBlank(fh);
	if ((format == PBM_BINARY || format == PGM_BINARY || format == PPM_BINARY)
	    && (fh2-fh) > 1)
		fh2 = fh + 1;

	/*  store image data offset and image format
	 */
	picinfo->User2 = (APTR)(fh2 - picinfo->FileHead);
	picinfo->User3 = (APTR)format;

	if (format == PGM_ASCII || format == PGM_BINARY)
		picinfo->Depth = 8;	/* a 256 grays image will be loaded */

	else if (format == PBM_ASCII || format == PBM_BINARY)
		picinfo->Depth = 1;	/* a B/W image will be loaded */
	else
		picinfo->Depth = 24;	/* a true color image will be loaded */

	/*  true color images can be previewed
	 */
	picinfo->PreviewDepth = (picinfo->Depth == 24) ? 24 : 0;

	/*  image format information has been stored
	 */
	picinfo->ProcessedData = PCDT_FORMAT;

	return(PIOERR_OK);
}

/*
 *  Progress requester information function:
 *  the load and save operations will issue <picture height> bumps.
 */
__asm LONG __saveds GetProgressBumps(register __a0 struct PictureInfo *picinfo)
{
	return((LONG)picinfo->Height);
}

/*
 *  This function gets a numeric value from an ASCII file
 *  (comments are skipped).
 */
static int GetFileNum(struct PictureInfo *picinfo)
{
	UBYTE buff[80], *bp;
	BOOL skip_comm, get_num;
	int val;

	bp = buff;
	skip_comm = get_num = FALSE;
	for (;;) {
		if (get_num)
			++bp;
		if (!picinfo->ReadFile(bp, 1))
			break;
		if (skip_comm)
		{
			if (*bp == '\n' || *bp == '\r' || *bp == 0)
				skip_comm = FALSE;
		}
		else
		{
			if (get_num)
			{
				if (*bp < '0' || *bp > '9')
					break;
			}
			else
			{
				if (*bp != ' ' || *bp != '\t' || *bp != '\n' || *bp == '\r')
				{
					if (*bp == '#')
						skip_comm = TRUE;
					else if (*bp >= '0' && *bp <= '9')
						get_num = TRUE;
				}
			}
		}
	}
	*bp = 0;
	return((int)(stcd_i(buff, &val) ? val : -1));
}

/*
 *  Image loading function
 */
__asm WORD __saveds ReadPicture(register __a0 struct PictureInfo *picinfo)
{
	struct Color *col;
	struct BitMap *bmap;
	UBYTE *r_plane, *g_plane, *b_plane, *rpl, *gpl, *bpl;
	LONG  bmap_mod;
	int r, g, b, maxval;
	float scale;
	WORD format, w, h, x, y, c;
	UBYTE byte_buff;

	/*  position the file at the beginning of image data
	 */
	if (picinfo->SeekFile(SKF_ABSOLUTE, (LONG)picinfo->User2) < 0)
		return(PIOERR_FILE_ERR);

	format = (WORD)picinfo->User3;

	if (format == PBM_ASCII || format == PBM_BINARY)
		maxval = 255;
	else
	{
		maxval = (int)picinfo->User1;
		if (maxval != 255)
			scale = 255.0 / (float)maxval;
	}

	/*  set the BINARY option using the current file information
	 *  (when the image will be saved again,
	 *   the original format will be used)
	 */
	PbmOptions[PBM_OPT_BINARY].Value = (format == PBM_BINARY ||
					    format == PGM_BINARY ||
					    format == PPM_BINARY) ? 1 : 0;

	if ((picinfo->ProcessData & PCDT_PALETTE) && picinfo->Palette)
	{
		/* algorithmically build a B/W or a gray palette
		 */
		col = picinfo->Palette;
		if (picinfo->Depth == 8)  /* PGM: gray levels palette */
		{			  /* (black fading to white)  */
			for (c = 0; c < 256; c++, col++)
			{
				col->Red = col->Green = col->Blue = c;
				col->EFlag = 0;
			}
		}
		else {	/* PBM: white+black palette */
			col->Red = col->Green = col->Blue = 255; /* white */
			col->EFlag = 0;
			col++;
			col->Red = col->Green = col->Blue = 0;   /* black */
			col->EFlag = 0;
		}
		picinfo->ProcessedData |= PCDT_PALETTE; /* color palette data are now available */
	}

	if ((picinfo->ProcessData & PCDT_IMAGE) && picinfo->BMap)
	{
		/* PCDT_IMAGE bit is set here to flag the presence
		 * of even partially loaded image data
		 * (see PIOERR_PARTIAL return code below)
		 */
		picinfo->ProcessedData |= PCDT_IMAGE;

		w = picinfo->Width;
		h = picinfo->Height;
		bmap = picinfo->BMap;

		if (picinfo->Depth == 24)	/* read PBM color data */
		{
			r_plane = bmap->Planes[0];
			g_plane = bmap->Planes[1];
			b_plane = bmap->Planes[2];
			bmap_mod = bmap->BytesPerRow;

			for (y = 0; y < h; y++)
			{
				rpl = r_plane;
				gpl = g_plane;
				bpl = b_plane;
				for (x = 0; x < w; x++, rpl++, gpl++, bpl++)
				{
					switch (format)
					{
						case PPM_ASCII:
							r = GetFileNum(picinfo);
							g = GetFileNum(picinfo);
							b = GetFileNum(picinfo);
							break;
						case PPM_BINARY:
							r = picinfo->ReadFile(&byte_buff, 1) ? byte_buff : -1;
							g = picinfo->ReadFile(&byte_buff, 1) ? byte_buff : -1;
							b = picinfo->ReadFile(&byte_buff, 1) ? byte_buff : -1;
							break;
					}
					if (r < 0 || g < 0 || b < 0)
						return(PIOERR_PARTIAL);

					if (maxval != 255)	/* scale to range 0...255 */
					{
						r = (float)r * scale + 0.5;
						g = (float)g * scale + 0.5;
						b = (float)b * scale + 0.5;
					}
					*rpl = r;
					*gpl = g;
					*bpl = b;
				}

				if (picinfo->BumpProgress)  /* one more progress requester step */
				{
					if (picinfo->BumpProgress())
						return(PIOERR_CANCEL);  /* user cancelled */
				}
				if (picinfo->PreviewDepth)
					picinfo->PreviewRow(bmap, y);	/* feed one more preview row */

				r_plane += bmap_mod;
				g_plane += bmap_mod;
				b_plane += bmap_mod;
			}
		}
		else	/* read B/W or gray image data */
		{
			/*
			 *  planar bitmap writing initialization
			 */
			picinfo->FastWritePix(bmap, FBMP_INIT, 0, 0);

			for (y = 0; y < h; y++)
			{
				for (x = 0; x < w; x++)
				{
					switch (format)
					{
						case PGM_ASCII:
						case PBM_ASCII:
							g = GetFileNum(picinfo);
							break;
						case PGM_BINARY:
						case PBM_BINARY:
							g = picinfo->ReadFile(&byte_buff, 1) ? byte_buff : -1;
							break;
					}
					if (g < 0)
						return(PIOERR_PARTIAL);

					if (maxval != 255)	/* scale to range 0...255 */
						g = (float)g * scale + 0.5;

					if (format == PBM_BINARY) /* write 8 B/W pixels */
					{
						for (c = 8; c > 0 && x < w; c--, x++, g <<= 1)
							picinfo->FastWritePix(bmap, x, y, (g & 0x80) ? 1 : 0);
						x -= 1;
					}
					else	/* write 1 (gray) pixel */
						picinfo->FastWritePix(bmap, x, y, g);
				}
				/*
				 *  flush pixel row buffer
				 */
				picinfo->FastWritePix(bmap, FBMP_FLUSH,0,0);

				if (picinfo->BumpProgress)  /* one more progress requester step */
				{
					if (picinfo->BumpProgress())
						return(PIOERR_CANCEL);  /* user cancelled */
				}
			}
		}
	}
	return(PIOERR_OK);
}

/*
 *  This function writes numeric values to an ASCII file
 *  (data is formatted in order to be readable in a 80 columns display)
 */
static BOOL WriteFileNum(int val, struct PictureInfo *picinfo)
{
	#define ROW_LIMIT  (70-4)

	static WORD pos = 0;	/* position counter */
	UBYTE buff[20], *b;
	LONG ln;

	if (val < 0)	/* just reset position */
	{
		pos = 0;
		return(TRUE);
	}
	b = buff;
	if (pos != 0)
		*b++ = ' ';  /* separator */

	b += stci_d(b, val);
	ln = b - buff;
	pos += ln;
	if (!picinfo->WriteFile(buff, ln))
		return(FALSE);

	if (pos >= ROW_LIMIT)	/* start a new line */
	{
		pos = 0;
		if (!picinfo->WriteFile("\n", 1))
			return(FALSE);
	}
	return(TRUE);
}

/*
 *  Image saving function
 */
__asm WORD __saveds WritePicture(register __a0 struct PictureInfo *picinfo)
{
	WORD format, n, w, h, x, y;
	UBYTE buff[80], *b;
	struct BitMap *bmap;
	struct Color *col, *col2;

	if (picinfo->Version < 3)
		return(PIOERR_BADVER);

	if ((picinfo->ProcessData & PCDT_IMAGE) == 0 ||
	    picinfo->BMap == NULL ||
	    picinfo->Palette == NULL)
		return(PIOERR_OK);

	format = NO_FORMAT;

	if (PbmOptions[PBM_OPT_AUTO].Value)  /* automatic PBM/PGM/PPM detection */
	{
		col = picinfo->Palette;
		for (n = 1 << picinfo->Depth; --n >= 0; col++)
		{
			if (!(col->Red == col->Green && col->Green == col->Blue))
				break;
		}
		if (n < 0)  /* the color palette just contains gray shades */
		{
			col = picinfo->Palette;
			col2 = col + 1;

			if (picinfo->Depth == 1 &&
			    ((col->Red == 0 && col2->Red == 255) ||
			     (col->Red == 255 && col2->Red == 0)))  /* it is a B/W image */
				format = PbmOptions[PBM_OPT_BINARY].Value ? PBM_BINARY : PBM_ASCII;
			else  /* it is a gray-level image */
				format = PbmOptions[PBM_OPT_BINARY].Value ? PGM_BINARY : PGM_ASCII;
		}
	}
	if (format == NO_FORMAT)  /* default format: PPM */
		format = PbmOptions[PBM_OPT_BINARY].Value ? PPM_BINARY : PPM_ASCII;

	/*
	 *  write file header
	 */
	b = buff;
	*b++ = 'P';
	*b++ = format + '1';
	*b++ = ' ';
	b += stci_d(b, picinfo->Width);
	*b++ = ' ';
	b += stci_d(b, picinfo->Height);

	if (format != PBM_ASCII && format != PBM_BINARY)
	{
		*b++ = ' ';
		b += stci_d(b, 255);
	}
	*b++ = '\n';
	if (!picinfo->WriteFile(buff, b-buff))
		return(PIOERR_FILE_ERR);

	WriteFileNum(-1, picinfo);  /* reset position */

	w = picinfo->Width;
	h = picinfo->Height;
	bmap = picinfo->BMap;

	/*
	 *  planar bitmap reading initialization
	 */
	picinfo->FastReadPix(bmap, FBMP_INIT, 0);

	for (y = 0; y < h; y++)
	{
		for (x = 0; x < w; x++)
		{
			col = picinfo->Palette +
			      picinfo->FastReadPix(bmap, x, y);

			switch (format) {
				case PBM_ASCII:
					if (!WriteFileNum(col->Red ? 0 : 1, picinfo))
						return(PIOERR_FILE_ERR);
					break;
				case PGM_ASCII:
					if (!WriteFileNum(col->Red, picinfo))
						return(PIOERR_FILE_ERR);
					break;
				case PPM_ASCII:
					if (!WriteFileNum(col->Red, picinfo) ||
					    !WriteFileNum(col->Green, picinfo) ||
					    !WriteFileNum(col->Blue, picinfo))
						return(PIOERR_FILE_ERR);
					break;
				case PBM_BINARY:
					/* write 8 B/W pixels */
					buff[0] = 0;
					for (n = 7; n >= 0 && x < w; x++, n--)
					{
						col = picinfo->Palette +
						      picinfo->FastReadPix(bmap, x, y);
						if (col->Red == 0)
							buff[0] |= 1 << n;
					}
					x -= 1;
					if (!picinfo->WriteFile(buff, 1))
						return(PIOERR_FILE_ERR);
					break;
				case PGM_BINARY:
					if (!picinfo->WriteFile(&col->Red, 1))
						return(PIOERR_FILE_ERR);
					break;
				case PPM_BINARY:
					buff[0] = col->Red;
					buff[1] = col->Green;
					buff[2] = col->Blue;
					if (!picinfo->WriteFile(buff, 3))
						return(PIOERR_FILE_ERR);
					break;
			}
		}
		if (picinfo->BumpProgress)  /* one more progress requester step */
		{
			if (picinfo->BumpProgress())
				return(PIOERR_CANCEL);  /* user cancelled */
		}
	}
	if (format == PBM_ASCII || format == PGM_ASCII || format == PPM_ASCII)
	{
		if (!picinfo->WriteFile("\n", 1))  /* add a LF to end the file */
			return(PIOERR_FILE_ERR);
	}

	/*  image data successfully saved
	 */
	picinfo->ProcessedData |= PCDT_IMAGE;

	return(PIOERR_OK);
}

__asm void __saveds IOLibCleanup(register __a0 struct PictureInfo *picinfo)
{
	/* no cleanup needed */
}

/*
 *  Standard option dispatcher.
 *
 *  This function does not usually need to be changed,
 *  unless the library supports run-time defined options.
 */
static void GetDataOption(struct DataOption *option,
			  struct DataOptionEntry *from)
{
	option->Type = from->Type;
	option->UITextStr = from->UITextStr;
	option->Flags = from->Flags;
	option->Value = from->Value;
	option->Min = from->Min;
	option->Max = from->Max;
	option->Default = from->Default;

	memcpy(option->String, from->String, sizeof(option->String));
	memset(option->Name, 0, sizeof(option->Name));
	if (from->Name)
		strcpy(option->Name, from->Name);

	memset(option->pad, 0, sizeof(option->pad));
}

/*
 *  Standard option query function
 *  (support for multiple picture types is included)
 */
__asm BOOL __saveds GetFirstOption(register __a0 struct DataInfo *dinfo,
				   register __a1 struct DataOption *option)
{
	LONG c = dinfo->Code;

	if (c < DATA_NUM) {
		DataOptionCount[c] = 0;
		if (DataOptionCount[c] <= DataOptionMax[c])
		{
			GetDataOption(option, Options[c] + DataOptionCount[c]);
			return(TRUE);
		}
	}
	return(FALSE);
}

/*
 *  Standard option query function
 *  (support for multiple picture types is included)
 */
__asm BOOL __saveds GetNextOption(register __a0 struct DataInfo *dinfo,
				  register __a1 struct DataOption *option)
{
	LONG c = dinfo->Code;

	if (c < DATA_NUM)
	{
		if (DataOptionCount[c] < DataOptionMax[c])
		{
			DataOptionCount[c] += 1;
			GetDataOption(option, Options[c] + DataOptionCount[c]);
			return(TRUE);
		}
	}
	return(FALSE);
}

/*
 *  Standard option set function
 *  (support for multiple picture types is included)
 */
__asm void __saveds SetOption(register __a0 struct DataInfo *dinfo,
			      register __a1 struct DataOption *option)
{
	struct DataOptionEntry *opt;
	LONG n, max, c;

	c = dinfo->Code;
	if (c < DATA_NUM && option)
	{
		max = DataOptionMax[c];
		/*
		 *  find an option with the given name
		 */
		for (n = 0, opt = Options[c]; n <= max; n++, opt++)
		{
			if (strcmp(option->Name, opt->Name) == 0) /* found */
			{
				opt->Value = option->Value;
				memcpy(opt->String, option->String, sizeof(opt->String));
				break;
			}
		}
	}
}

/*
 *  Standard option reset function
 *  (support for multiple picture types is included)
 */
__asm void __saveds ResetOptions(register __a0 struct DataInfo *dinfo)
{
	struct DataOptionEntry *opt;
	LONG n, max, c;

	c = dinfo->Code;
	if (c < DATA_NUM)
	{
		max = DataOptionMax[c];
		for (n = 0, opt = Options[c]; n <= max; n++, opt++)
			opt->Value = opt->Default;
	}
}

/*
 *  Private PersonalIO functions
 */
__asm WORD __saveds PersonalIOPrivate1()
{
	return(PIOERR_CANCEL);
}

__asm WORD __saveds PersonalIOPrivate2()
{
	return(PIOERR_CANCEL);
}

__asm WORD __saveds PersonalIOPrivate3()
{
	return(PIOERR_CANCEL);
}
