/*-----------------------------------------------------------------------75
** File: PCDOSLIB.0rB.C  By: s_dubrovich@yahoo.com
** ?(c): COPYLEFT
** Last: 18-Jun-11 06:34:34 PM  	By: s_dubrovich@yahoo.com
** Prev: 11-Jun-11 03:01:50 PM,16-Jun-11 01:02:20 PM,17-Jun-11 07:05:37 AM
** Vers: 0r7
** 02-Jun-11 08:50:35 AM - added DebugFlag
** 02-Jun-11 08:50:35 AM - added fclose notification of fp#.
** 09-Jun-11 07:23:44 PM - conv gets to using handle STDIN, added; getstr,
**  getcstr, fgetline.
** 10-Jun-11 01:58:35 PM - v.0r6, edits
** 11-Jun-11 01:17:35 PM - added strcpy back in. prior was chgd to strxcpy.
** 11-Jun-11 03:01:50 PM - fix gets
** 16-Jun-11 01:02:20 PM - fix getc`in_port->initialize.
** 17-Jun-11 07:05:37 AM - added putsline()
** 18-Jun-11 06:34:34 PM - added fputc() note, fix comma instead of semicolon.
*/
/*-----------------------------------------------------------------------75
** File: pcdoslib.0r8.c	By: s_dubrovich@yahoo.com
** ?(c): COPYLEFT
** Last: 30-May-11 11:48:34 AM
** Prev: 21-May-11 01:55:28 PM,21-May-11 02:39:13 PM,23-May-11 07:26:13 AM
** Init: 07-May-11 09:05:49 AM
** Vers: 0r8
** Note: This is a pcdos IO library, support to small-c.
**  small-c doesn't handle: char *list[numb] - declare as int's.
**-----------------------------------------------------------------------75
** 07-May-11 09:05:49 AM - v.0r1, initial, puts()
** 07-May-11 09:34:18 AM - edits.
** 08-May-11 08:08:10 AM - explict .cseg & .dseg in #asm
** 08-May-11 09:31:03 AM - chg stack frame to pass address to store CF val.
** 08-May-11 10:19:02 AM - ren exit->_exit
** 09-May-11 11:48:55 AM - edits.
** 10-May-11 11:50:53 AM - expanded creat()
** 10-May-11 02:19:10 PM - fix hptr[FNAME] -> &hptr[FNAME]
** 11-May-11 02:11:03 PM - v.0r3, creat() works in v.0r2, chg method to
**  if fopen() fails on fnf, creat() file. -added DEBUG flag for msgs.
**  fopem() modes "R","W".
** 12-May-11 01:06:18 PM - build out functions..
** 13-May-11 07:53:55 AM - v.0r4, combating access denied, use fn 6Ch.
** 13-May-11 11:32:25 AM - chg'd fopen, fclose.
** 14-May-11 09:08:47 AM - fix str termination, save _CX_ on error.
**  -version 0r4- chgs ABI from stack vars to static register vars.
** 15-May-11 07:57:55 AM - v.0r4, chg ABI.
** 15-May-11 11:08:35 AM - chg'd fseek var.
**   - v.0r6, chg'd file mode, _IOD layout.
** 18-May-11 08:38:17 AM - v.0r7, chg File Modes recognition. 
** 19-May-11 09:12:54 PM - fix typo in fopen().
** 21-May-11 08:33:39 AM - more work on getc() and fread().
** 21-May-11 01:55:28 PM - inport -> &inport, getc()`0->eof.
** 21-May-11 02:39:13 PM - added name exit:
** 23-May-11 07:26:13 AM - chg use of strcpy to linecpy to strip CR in gets().
** 30-May-11 11:48:34 AM - v.0r8, edits, getc() edited.
** 01-Jun-11 11:03:23 PM - added fgets(), fputs(), fgetpos(), fsetpos()
**-----------------------------------------------------------------------75
*/

/** Req'd IO Functions for Small-c              **/
/** getc(){;} gets(){;} putc(){;}               **/
/** putchar(){;} fopen(){;} fclose(){;}         **/

#define DEBUG 1	/** set to 1 to emit runtime state messages, else 0 **/
			/** #define NULL  0 **/
/** -see include.h..
#define STDIN	0
#define STDOUT	1	
#define STDERR	2
**/

#define MAXLENGTH 128	/** max input line length including CR,LF **/

/*
** -= Handle Files =-
**
** 1. Create an ASCIIZ filename string.
** 2. OPEN or CREATE the file.
** 3. SEEK a file pointer to a position in the file.
** 4. READ from or WRITE to file at the SEEK position.
** 5. CLOSE the file.
*/

/** pcDos Handle Functions **/
#define FCREAT_FN 60	/** 3Ch **/
#define FOPEN_FN	61	/** 3Dh **/
#define FCLOSE_FN 62	/** 3Eh **/
#define FREAD_FN	63	/** 3Fh **/
#define FWRITE_FN	64	/** 40h **/
#define FDELETE_FN 65	/** 41h **/
#define FSEEK_FN	66	/** 42h **/
#define EFOPEN_FN 108	/** 6Ch **/

#define SEEK_BEG	0	/** base origin from beginning of file **/
#define SEEK_CUR	1	/** base origin from current position  **/
#define SEEK_END	2	/** base origin from end position      **/

/** #if PCDOS		*****************************/
#define EXIT         0	/* Exit to pcDOS            */
#define CONIN        1	/* direct echoing con input */
#define CONOUT       2	/* Direct console output    */
#define LSTOUT       5	/* Direct list device output*/
#define CONIO        6	/* Direct console I/O       */
#define C_WRITESTR   9	/* Console string output    */
#define STDIN_fn10  10	/* Read console buffer      */
#define C_STAT      11	/* Get console status       */
#define OPEN        15	/* OPEN a disk file         */
#define CLOSE       16	/* Close a disk file        */
#define SEARCHF     17	/* Search for first         */
#define SEARCHN     18	/* Search for next          */
#define DELETE      19	/* Delete a disk file       */
#define SEQREAD     20	/* seq read                 */
#define SEQWRITE    21	/* seq write                */
#define CREATE      22	/* Create a disk file       */
#define F_RENAME    23	/* Rename a disk file       */
#define SETDMA      26	/* Set DMA address          */
#define B_READ      33	/* Read Random record       */
#define B_WRITE     34	/* Write Random record      */
#define FILSIZ      35	/* Compute File Size        */
/** #endif              *****************************/

#define BAD	(-1)
/* #define EOF	(-1)
** #define CR	13
** #define LF	10
*/

#define FBUFFSIZE	128	/** dta buffer size **/
				/** word - File Open Mode **/
#define MODE_RD	0	/** "r" **/
#define MODE_WR	1	/** "w" **/
#define MODE_RW	2	/** "+" added to "r" or "w" means RW **/
#define MODE_APPD	8	/** means open and seek to end of file, for append **/
#define MODE_TXT	16384	/** 4000h, is text file. **/
#define MODE_BIN	32768	/** 8000h is binary file, flag. **/
#define MODE_CL	-1	/** File has been closed **/

/** Define File Descriptor Indexes - _IOD **/
#define FNAMEPTR	0	/* word, PTR to caller's Path & Filename       */
#define FMODE	2	/* word, access, 0`Read,1`Write,2`R/W, etc.    */
#define FBUFRPTR	4	/* File DTA (io buffer for ea handle)          */
#define LEN_IOD	6	/* 16 + 128 buffer size                        */

/*-----------------------------------------------------------------------75
**  Static Data for OSfn_ Calls/Returns
*/
int DebugFlag;	/** promote or suppress runtime messages **/
int resultflg;	/** static var reflecting OSfn_ carry flag return **/
			/** 0 = success, 1 = error. **/
int _AX_,_BX_,_CX_,_DX_,_SI_,_DI_;	/** assign values before OSfn(); **/

/*-----------------------------------------------------------------------75
** Toggle Debug messaging state.
*/

StateDegugFlg(n) int n;
{
	DebugFlag = n;	
}


/*-----------------------------------------------------------------------75
** Copy src string until null, to dest string buffer.
** Returns: count of characters copied.
*/

strxcpy(dest,src) char *dest, *src;
{
	int count;

	count = 0;
	while (*dest++ = *src++)
		{
		count++;
		}
	*dest = 0;		/** null terminate string **/
	return (count);
}

/*-----------------------------------------------------------------------75
** -ANSI- char *strcpy(char *dest, char *src); return: dest.
** Copy src string, null inclusive, to dest string buffer.
*/

strcpy(dest,src) char *dest, *src;
{
	int count,orig_dest;

	count = 0;
	orig_dest = dest;	/** save to return per ANSI **/
	while (*dest++ = *src++)
		{
		count++;
		}
	*dest = 0;		/** null terminate string **/
	return (orig_dest);
}

/***-------------------------------------------------------------------***/
/** --------------------= S I M P L E   I / O =------------------------ **/
/***-------------------------------------------------------------------***/


/***-------------------------------------------------------------------**75
*** codify EOL sequence... to STDOUT
**/

NLfn()
{
	putchar(CR); putchar(LF);
}

/*-----------------------------------------------------------------------75
** must be null terminated, STDOUT (ok) -doesn't append '/n'.
*/

char out_bufr[MAXLENGTH];

putstr(prntstr) char *prntstr;
{
	int count, result;

	count = strxcpy(out_bufr,prntstr); /** cpy until null **/
	if (count == 0) return (-1);

	result = fwrite(&out_bufr[0],1,count,STDOUT);
		/** result is bytes written **/
}


/*-----------------------------------------------------------------------75
** -ANSI- int puts(char *str);   string output to STDOUT, appends '\n'.
** Ret`0`ok .else. `NZ`err
*/

char tbuff[MAXLENGTH];

puts(str) char *str;
{
	int count, result;

	count = strxcpy(tbuff,str);
	if (count == 0) return (-1);

	result = fwrite(&tbuff[0],1,count,STDOUT);
		/** result is bytes written **/
	NLfn();
}
/** eo puts **/

/*-----------------------------------------------------------------------75
** -non-standard- int putsline(char *str);   string output to STDOUT, does
** not append '\n'.
** Ret`0`ok .else. `NZ`err
** Requires the above: char tbuff[MAXLENGTH];
*/

putsline(str) char *str;
{
	int count, result;

	count = strxcpy(tbuff,str);
	if (count == 0) return (-1);

	result = fwrite(&tbuff[0],1,count,STDOUT);
		/** result is bytes written **/
} /** eo putsline **/

/*-----------------------------------------------------------------------75
** STDIN get line input..
*/

char in2_bufr[MAXLENGTH];  /** used for STDIN buffer re: getstr,getcstr. **/

/*-----------------------------------------------------------------------75
** str input thru file handle STDIN.
** note: input stops at [enter], then CR,LF appended.
**  -append null to CR,LF pair.
*/

getstr()
{
	int result, ndx;

	result = fread(&in2_bufr[0],1,MAXLENGTH,STDIN);
	ndx = 0;

	while (1)
		{
		if (in2_bufr[ndx] == LF)
			{
			in2_bufr[++ndx] = 0;
			break;
			}
		if (in2_bufr[ndx] == 0) break;

		ndx++;
		}
}

/*-----------------------------------------------------------------------75
** str input thru file handle STDIN. 
** note: input stops at [enter], CR,LF appended.
**  -replaces CR with null.
*/

getcstr()
{
	int result, ndx;

	result = fread(&in2_bufr[0],1,MAXLENGTH,STDIN);
	ndx = 0;

	while (1)
		{
		if (in2_bufr[ndx] == CR)
			{
			in2_bufr[ndx++] = 0;
			in2_bufr[ndx] = 0;
			break;
			}
		if (in2_bufr[ndx] == 0) break;

		ndx++;
		}
}


/*-----------------------------------------------------------------------75
** --------------= F I L E   I / O =-------------- **
***-----------------------------------------------***
** NOTE: use HANDLE functions of 3Ch and up. 
**  -see also Fn 6Ch for pcdos v.4 (not implemented)
*/

/**- These first 6 functions are required by a small-c implementation. -**/

/*-----------------------------------------------------------------------75
** (i.) define getc(){;}
** int getc(FILE *fp); -read next unsigned chr from file, returns int.
**  Returns: unsigned char cast to int, or -1 (EOF) on EOF or read error.
**
**  pcDos handle function: AH`3Fh, BX`handle#, CX`rd_cnt, DS:DX`&buffer.
** Returns: NC`success, AX`#bytes_read .else. CF`error, AX`err_code =
**  00h`EOF_on_attempt, 05h`access_denied, 06h`invalid_handle.
** .if. (success) & .if. (AX < CX) a partial read before EOF.
*/

int in_port;  /** 1 chr global input buffer specific to getc() **/

getc(fp) int fp;
{
	int cnt;

	in_port = 0;			/** init to avoid cast garbage, -1 **/
	cnt = fread(&in_port,1,1,fp);

	/** cnt should equal 1, or -1 on err **/

	if (cnt == -1)  /** .then. error. **/
		{
		in_port = EOF;
		}
	else if (cnt == 0) /** effectively eof **/
		{
		in_port = EOF;
		}
	return (in_port);  /** EOF or raw byte chr cast to int **/
}

/*-----------------------------------------------------------------------75
** (ii.) define gets(){;}
** char *gets(char *buffer); -read next line of characters from STDIN to
**  buffer.  Reads STDIN until newline or eof, discards newline and
**  appends null to input. (A null terminated string.)
** - pcDos AH`0Ah, DX`fn10_buffer, STDIN_fn10, No Returned Values.
**  buffered input is terminated by 0Dh, so chg to null.
*/

char stdinbufr[258];  /** temp buffer for pcdos fn **/

gets(bufr) char *bufr;
{
	int result,i,j;

	stdinbufr[0] = 255;
	i = 255; j = 2;

	while (i--) stdinbufr[j++] = 0;	/** zero out buffer **/

	_AX_ = STDIN_fn10; _BX_ = 0; _CX_ = 0; _DX_ = &stdinbufr[0];
	_SI_ = 0; _DI_ = 0;
	OSfn_();
	j = 1;
	result = stdinbufr[j];
	j = j + result;
	j++;
	stdinbufr[j] = 0;		/** null terminate input as str **/
	j = 2;
	result = strcpy(bufr,&stdinbufr[2]);
		/** copy up to CR, null appended **/
		/** result per ANSI is &bufr[0] **/

	return (stdinbufr[1]); /** count of chrs read **/
}

/*-----------------------------------------------------------------------75
** (iii.) putc(){;} 
** -ANSI- int putc(int chr,FILE *fp); ret`chr`ok .else. EOF`on_error.
** Write chr to file fp.
**  note: only return EOF on File Error, ret null or
**  chr only.  (echo back chr means success)
*/

int out_port;

putc(chr,fp) int chr, fp;
{
	int result;

	out_port = chr;
	result = fwrite(&out_port,1,1,fp);
		/** result is bytes written **/
}

/*-----------------------------------------------------------------------75
** (iv.) define putchar(){;}
** -ANSI_ int putchar(int c);
** Write chr to file fp STDOUT.
**  note: only return EOF on File Error, ret null or
**  chr only.  (echo back chr means success)
*/

int putchar_port;		/** 1 chr buffer, int_sz **/

putchar(chr) int chr;	/** as a Handle Fn **/
{
	int retval, result;

	putchar_port = chr;
	result = fwrite(&putchar_port,1,1,STDOUT);
		/** result is bytes written **/
}

/*-----------------------------------------------------------------------75
** -= DOS v 4+ use AH`6Ch =- requires SI`asciiz filename.
**  (v.) define fopen(){;}
** FILE *fopen(char *filename, char *access); Returns fp#, or NULL error.
**  pcDos AX`6Ch, BX`OpenModeBitMap, CX`FileAtrributesBitMap,
**  DX`ActionFlagBitMap, DS:SI`Pointer to ASCIIZ pathname.
** RETURNS: CF`error & AX`error_code .or. NC`success & CX`Actionflag where
**  1 - file existed and was opened.
**  2 - file did not exist, created.
**  3 - file existed and was replaced.
** -use "w" -write, "r" -read, "a", -append to eof. Suffix of "+" means
** read and write combination, modes 0..5.
*/

fopen(fname,mode) char *fname; char *mode;
{
	int fp,ResultAct,openmode,mode_fn,fattr,actionflg;
	char *hptr,*nstr,*pstr;

	/** 1st check & set access mode is "r","w","a","+" **/

	if (mode[0] == 'r')
		{
		openmode = 0;
		if (mode[1] == '+') openmode = openmode + 3;
		}
	else if (mode[0] == 'w')
		{
		openmode = 1;
		if (mode[1] == '+') openmode = openmode + 3;
		}
	else if (mode[0] == 'a')
		{
		openmode = 2;
		if (mode[1] == '+') openmode = openmode + 3;
		}
	else 	{
		puts("Bad File Open Mode.");
		openmode = -1;
		resultflg = 1;	/** error **/
		fp = NULL;
		return (fp);	/** error, exit subroutine. **/
		}

	/** map openmode to pcDos fn | 0=R, 1..2=W, 3+ =RW **/

	if (openmode < 2)	/** 0=R, 1=W **/
		{
		mode_fn = 24576 + openmode;  /** 24576 is 6000h, BX **/
		}
	else if (openmode == 2) mode_fn = 24576 + 1; /** write only-append **/
	else openmode = 24576 + 2;	/** otherwise RW for '+' **/

	fattr = 0;			/** R,W,A, normal file attr, CX **/
	actionflg = 17;		/** 0011h, DX, create or open **/
	ResultAct = 0;		/** initialize control variable **/

	_AX_ = EFOPEN_FN; _BX_ = mode_fn; _CX_ = fattr; _DX_ = actionflg;
	_SI_ = fname; _DI_ = 0;
	fp = OSfn_();

	if (resultflg)  /** .then. error. **/
		{
		NLfn();
		putstr("Open file error: ");
		nstr = itoa(fp);
		puts (nstr);
		fp = NULL;
		return (fp);	/** error, EXIT subroutine. **/
		}

	else	{			/** fopen success **/
		NLfn();
		putstr("Open file success: ");
		nstr = itoa(fp);
		puts (nstr);
		ResultAct = _CX_;

/*****	nstr = itoa(ResultAct);
		puts (nstr);
		NLfn();
*****/
		if (ResultAct == 1)
			{
			puts(" file existed and was opened.");
			}

		else if (ResultAct == 2)
			{
			puts(" file non-existed, created.");
			}

		else if (ResultAct == 3)
			{
			puts(" file existed and was replaced.");
			}
/*******
		else	{
			putstr(" unknown file action taken.. ");
			pstr = itoa(ResultAct);
			puts (pstr);
			}
*******/
		}  /** eo else **/

/** with the file opened, check if 'a' append, meaning fseek to eof **/

	if ((openmode == 2) | (openmode == 5)) fseek(fp, 0, 0, SEEK_END);

	return (fp); 	/** pass back handle number, 0 or valid# **/
}				/** EO fopen() **/

/*-----------------------------------------------------------------------75
** (vi.) define fclose(){;}
** int fclose(FILE *fp);
**  pcDos AH`3Eh, BX`file_handle.
** Returns: NC`success or CF`error, AX`err_code`6`invalid handle.
** FCLOSE_FN.  Perform the necessary housekeeping to empty buffers and
** break all connections to the file associated with fp.  A successful
** close returns zero.  An error returns EOF.
*/

fclose(fp) int fp;
{
	int  errcode, i, ndx, ndx2;
	char *hptr,*nstr;

	if (fp > 2)
		{
		_AX_ = FCLOSE_FN; _BX_ = fp; _CX_ = 0; _DX_ = 0;
		_SI_ = 0; _DI_ = 0;
		 errcode = OSfn_();
		}
	else	{
		puts(" -Invalid Handle: (0..2) for fclose. ");
		return (-1);
		}

	if (resultflg)  /** .then. error, ck = 6 **/
		if (errcode == 6)
			{
			puts(" -Invalid Handle for fclose. ");
			nstr = itoa(fp);
			puts (nstr);
			return (-1);
			}
		else	{
			puts(" -undetermined fclose error.");
			return (-1);
			}
	else	{  /** fclose succeeded **/
		NLfn();
		putstr("Close file success. ");
		nstr = itoa(fp);
		puts (nstr);
		return (0);
		}
}	/** EO FCLOSE_FN **/

/***
**** END of 6 Required Interface Functions of Small-C ***
***/

/*-----------------------------------------------------------------------75
** -ANSI- char *fgets(char *bufr, int limit, FILE *fp);
** Read a line of characters from file fp, store to bufr[limit].  Reads
** (which ever occurs first); up through \n, limit -1, or to EOF, and
** appends null termination into bufr[].
** Returns: On success: ptr to bufr.  On error: NULL.
** "\n" is taken as CR,LF for pcDos.
** -non-standard- static int fgets_cnt; holds count of chrs.
*/

int fgets_cnt;

fgets(fbufr, lnlimit, fp) char *fbufr; int lnlimit,*fp;
{
	int la_chr, chr, i;

	i = 0;
	la_chr = getc(fp);
	if (la_chr == EOF)		/** eof, at start **/
		{
		if (DebugFlag) puts("Empty File?");
		fgets_cnt = i;		/** zero length **/
		return (NULL);
		}
	else	fbufr[i++] = la_chr;

	while (--lnlimit)  /** count down to zero **/
		{
		chr = la_chr;
		if (la_chr == CR) lnlimit = 1;  /** 1st newline chr hit **/
		la_chr = getc(fp);
		if (la_chr == EOF)
			{	/** EOF reached without "\n" **/
			fbufr[i] = 0;
			fgets_cnt = i;
			return (NULL);
			}
		fbufr[i++] = la_chr;
		}
	fbufr[i] = 0;
	fgets_cnt = i;		/** record count of chrs in line. **/
	return (&fbufr[0]);
}

/*-----------------------------------------------------------------------75
** -ANSI- int fputs(char *str, FILE *fp);
**  writes a string of characters to fp, not including the null terminator.
**  Does not append newline (\n).
** Returns: On success: 0.  On error: non-zero.
*/

fputs(str, fp) char *str; int fp;
{
	int i,c,n;

	i = 0;
	n = MAXLENGTH;
	while (n--)
		{
		c = str[i++];
		if (c == 0) return (0);  /** done with copy to file **/
		putc(c,fp);
		}
	/** error state **/
	return (-2);
}

/*-----------------------------------------------------------------------75
** -ANSI- int fputc(int chr, FILE *fp);
**  writes a character to fp, not including the null terminator.
** Returns: On success: chr.  On error: EOF.
** -see putc(chr,fp);
*/



/*-----------------------------------------------------------------------75
** fgetstr(bufr, MAXLENGTH, fp) !not standard! fetch up to MAXLENGTH chrs
** from input file *fp into bufr[MAXLENGTH], strip NL replace with null.
*/

fgetline(fbufr,lnlimit,fp) char *fbufr; int lnlimit, fp;
{
	int result, i;

	i = 0;
	result = fgets(fbufr, lnlimit, fp); /** get next line from fp **/

	if (result == EOF) return (EOF);
	while (lnlimit--)
		{
		if (fbufr[i] == CR)
			{
			fbufr[i] = 0;	/** CR spot **/
			fbufr[i+1] = 0;	/** LF spot **/
			return (i);		/** return count of chrs in str **/
			}
		i++;
		}
}

/*-----------------------------------------------------------------------75
**  define creat(){;}
** int creat(char *fn, int mode);  -returns 0`success, >0`error.
**  pcDos AH`3Ch, CX`attr`0, DX`ASCIIZ`filename. Returns: NC`AX`fp_handle,
**  -or- CF`AX`err_code.  NOTE: creat() destroys existing file!!!
** CX`file_attr=0 for normal.  mode=0`read,=1`write,=2`rd&wr, however,
** OSfn_ call ignores mode for creat();
*/

/* this is an internal function to fopen(), and so is not supported as an
** independant function that can be called.
*/
	/** eo creat() **/

/*-----------------------------------------------------------------------75
** -ANSI-
**  size_t fwrite(void *buffer, size_t size, size_t number, FILE *fp);
** Returns: number of size_t items written. If returned number < nuber
** requested to be written, then there was a write error.
**
** (semi)-ANSI-
** fwrite(buffer,size,number,fp) char *buffer; int size, number, fp;
** - fwrite writes (size * number) of bytes from the buffer to the fp.
** - returns the number of bytes written. (non-conforming behavior as item
**   can be other than byte in size, but this returns byte count.)
** - the position of the write is from the last write (automatic) position.
*/

fwrite(fbufr, item_sz, item_cnt, fp)
char *fbufr; int item_sz, item_cnt, fp;
{
	int byte_cnt, ret_val;

	byte_cnt = item_sz * item_cnt;
	_AX_ = FWRITE_FN; _BX_ = fp; _CX_ = byte_cnt; _DX_ = fbufr;
	_SI_ = 0; _DI_ = 0;
	ret_val = OSfn_();

	if (resultflg)  /** .then. error, ck error code **/
		{
		if (ret_val == 5)
			{
			puts("-fwrite: access denied.");
			return (-1);
			}
		if (ret_val == 6)
			{
			puts("-fwrite: Invalid Handle.");
			return (-1);
			}
		else	{
			puts("-undetermined fwrite error.");
			return (-1);
			}
		}
 	/** fread success, return number of bytes written **/
	/** if (ret_val < byte_cnt) -partial record written **/

	else	return(ret_val);
}

/*-----------------------------------------------------------------------75
** -ANSI-
** size_t fread(void *buffer, size_t size, size_t number, FILE *fp);
**  reads data items from file fp, stores them to buffer.  size_t specifies
**  item size in bytes.  size_t it an unsigned int data type that results
** from using the 'sizeof' operator.
**
** fread(buffer,size,number,fp) char *buffer; int size, number, fp; 
** - fread reads (size * number) of bytes from fp into buffer.
** - returns number of bytes read. (non-conforming behavior)
** - the position of the read is from the last seek (automatic) position.
**
**  pcDos handle function: AH`3Fh, BX`handle#, CX`rd_cnt, DS:DX`&buffer.
** Returns: NC`success, AX`#bytes_read .else. CF`error, AX`err_code =
**  00h`EOF_on_attempt, 05h`access_denied, 06h`invalid_handle.
** .if. (success) & .if. (AX < CX) a partial read before EOF.
*/

fread(fbufr,item_sz,item_cnt,fp) char *fbufr; int item_sz,item_cnt,fp;
{
	int byte_cnt, ret_val;

	byte_cnt = item_sz * item_cnt;
	_AX_ = FREAD_FN; _BX_ = fp; _CX_ = byte_cnt; _DX_ = fbufr;
	_SI_ = 0; _DI_ = 0;
	ret_val = OSfn_();  /** results passed back from INT 21h in AX **/

	if (resultflg)  /** .then. error, ck error code **/
		{
		if (ret_val == 0)
			{
			puts("-fread: EOF.");
			return (-1);
			}
		if (ret_val == 5)
			{
			puts("-fread: access denied.");
			return (-1);
			}
		if (ret_val == 6)
			{
			puts("-fread: Invalid Handle.");
			return (-1);
			}
		else	{
			puts("-undetermined fread error.");
			return (-1);
			}
		}
	else	{ /** fread success, return number of bytes read **/
		return (ret_val);
		}
}

/*-----------------------------------------------------------------------75
** -ANSI- int fseek(FILE *fp, long offset, int origin);
** fseek changes the file position indicator of the file fp, where offset
** is relative to the 'origin' mode desired; BOF, current position, or EOF.
**
** fseek(fp, offset_hiword, offset loword, mode);
**  AH`42h, AL`origin index
** Change the File Ptr Location to a position relative to; a. the start of
** the file, or b. the current position in thefile, or c. the end of the
** file.  Mode`HiByte`AX`a.=0,b.=1,c.=2, BX`handle, CX`high word of
** double word offset, DX`low word of double word offset.
** Returns: NC`success & DX:AX`new fp position.  CF`error,AX`err_code
**  1`invalid function, or 6`invalid handle.
*/

int SeekLo, SeekHi, ThisFileHandle; /** AX, DX, returned position. **/

fseek(fp, offs_hi, offs_lo, origin) int fp, offs_hi, offs_lo, origin;
{
	int seek_mode, ret_val;

	seek_mode = (origin << 8) + FSEEK_FN;
	_AX_ = seek_mode; _BX_ = fp; _CX_ = offs_hi; _DX_ = offs_lo;
	_SI_ = 0; _DI_ = 0;
	ret_val = OSfn_();

	if (resultflg)  /** .then. error, ck error code **/
		{
		if (ret_val == 1)
			{
			puts(" -seek: invalid function (file sharing).");
			return (-1);
			}
		if (ret_val == 6)
			{
			puts(" -seek: Invalid Handle.");
			return (-1);
			}
		else	{
			puts("-undetermined seek error.");
			return (-1);
			}
		}
	else	{	/** successful seek, record new position **/
		SeekLo = _AX_;
		SeekHi = _DX_;
		ThisFileHandle = _BX_;
		}
}

/**
*** NOTE: ANSI behavior on the pair fgetpos() and fsetpos() is such that
*** fgetpos() records the file pointer position at some point in your
*** algorithm, and fsetpos() returns to that point by setting what was
*** recorded by fgetpos().
**/

/*-----------------------------------------------------------------------75
** -ANSI- int fsetpos(FILE *fp, fpos_t *pos);
** Sets the file position indicator to the value pointed to by 'pos'.  The
** 'pos' argument must point to a value obtained by a prior call to the
** fgetpos() function.
** Returns: 0 if successful, NZ on error.
**
** fsetpos(fp, offset);	-> AH`42h, 
** Change the File Ptr Location to a position relative to the start of
** the file.
**  Method`HiByte`AX`0, BX`handle, CX`high word of
** double word offset, DX`low word of double word offset.
** Returns: NC`success & DX:AX`new fp position.  CF`error,AX`err_code
**  1`invalid function, or 6`invalid handle.
*/

fsetpos(fp, pos) int fp, *pos;
{
	int seek_mode, ret_val, origin;

	origin = 0;	/** 0 = position from beginning of file. **/

	seek_mode = (origin << 8) + FSEEK_FN;

	_AX_ = seek_mode; _BX_ = fp; _CX_ = pos[1]; _DX_ = pos[0];
	_SI_ = 0; _DI_ = 0;
	ret_val = OSfn_();

	if (resultflg)  /** .then. error, ck error code **/
		{
		if (ret_val == 1)
			{
			puts(" -seek: invalid function (file sharing).");
			return (-1);
			}
		if (ret_val == 6)
			{
			puts(" -seek: Invalid Handle.");
			return (-1);
			}
		else	{
			puts("-undetermined seek error.");
			return (-1);
			}
		}
	else	{	/** successful seek, record new position **/
		SeekLo = _AX_;
		SeekHi = _DX_;
		ThisFileHandle = _BX_;
		}
}

/*-----------------------------------------------------------------------75
** -ANSI- int fsetpos(FILE *fp, fpos_t *pos);
** Stores the current value of the file position indicator for fp to 'pos'.
** Returns: 0 if successful, NZ on error.
**
** fgetpos(fp, pos);	AH`42h, AL`origin index=curr position.
** Change the File Ptr Location to a position relative (0) to the current
** position in the file. 
**
** Returns: 0 if successful, sets int values in array pos, pos[0]`offset
**  low_word, pos[1]`offset high_word, from BOF.
*/

fgetpos(fp, pos) int fp, *pos;
{
	int seek_mode, ret_val, origin;

	origin = 1;	/** 1 = from curr. pos. rets current position **/

	seek_mode = (origin << 8) + FSEEK_FN;
	_AX_ = seek_mode; _BX_ = fp; _CX_ = 0; _DX_ = 0;
	_SI_ = 0; _DI_ = 0;

	ret_val = OSfn_();	/** call to OS, passing register variables **/

	if (resultflg)  /** .then. error, ck error code **/
		{
		if (ret_val == 1)
			{
			puts(" -seek: invalid function (file sharing).");
			return (-1);
			}
		if (ret_val == 6)
			{
			puts(" -seek: Invalid Handle.");
			return (-1);
			}
		else	{
			puts("-undetermined seek error.");
			return (-1);
			}
		}
	else	{	/** successful seek, record new position **/
		pos[0] = _AX_;
		pos[1] = _DX_;
		return (0);
		}
}

/*-----------------------------------------------------------------------75
** fdelete();  -delete file, name passed in a string array.
**
*/
fdelete(fname) char *fname;
{
	int errcode;
	_AX_ = FDELETE_FN; _BX_ = 0; _CX_ = 0; _DX_ = fname;
	_SI_ = 0; _DI_ = 0;
	errcode = OSfn_();
}

/*-----------------------------------------------------------------------75
**  ReportExtErr();  pcDos AH`59h
**  Provides additional information about errors after execution of int 21h
**  sevices that set the carry flag.
*/

/*-----------------------------------------------------------------------75
**  define set_dta(){;}
**  pcDos AH`2, DL`chr
*/

/***-------------------------------------------------------------------***/
/** --------------------= O S   I N T E R F A C E =-------------------- **/
/***-------------------------------------------------------------------***/
/*
** OSfn_(); static variables hold register values to pass and return.
**  
*/

 #asm
  [SECTION .cseg]
OSfn_:
	mov	ax, [_AX_]
	mov	bx, [_BX_]
	mov	cx, [_CX_]
	mov	dx, [_DX_]
	mov	SI, [_SI_]
	mov	DI, [_DI_]
	cmp	al, 0		;; Fn# 0 is exit
	je	_exit
	xchg	ah, al	;; swap fn to AH for pcDOS int 21h
	int	21h

	mov	[_AX_], ax
	mov	[_BX_], bx
	mov	[_CX_], cx
	mov	[_DX_], dx
	mov	[_SI_], SI
	mov	[_DI_], DI

	jc	.errflg	;; Int 21h returns CF set .if. error.

	mov	[resultflg], word 0		;; no carry = success.

	MOV	BX, AX	;; for Prim`BX, Secd`DX. Caller expects primary
	RET			;; Caller cleans the stack.

.errflg:
	mov	[resultflg], word 1		;; carry = error in AX, ->BX

	MOV	BX, AX	;; for Prim`BX, Secd`DX.
	RET			;; Caller cleans the stack.

;;-----------------------------------------------------------------------75
;;** -= Exit Function =- **
;;

exit:				;; duplicate name.
_exit:			;; pause for keypress before return.
	mov  ah, 0
	int  16h		;; RomBios wait for keypress.

	mov	ax, 4C00h	;; pcDos quit executable.
	int	21h

  [SECTION .dseg]
result_flg_ptr	dw 0	;; address passed to store results_flag

  [SECTION .cseg]
 #endasm

/**-- eo pcdoslib.c --**/

8:42 PM 6/20/2011