/*-
 * Copyright (c) 2006 Robert N. M. Watson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef _DOS_H_
#define	_DOS_H_

#include <limits.h>
#include <unistd.h>

/*
 * Weird DOS-esque externs.
 */
extern int	_osmajor;
extern int	_osminor;

/*
 * Less weird externs.
 */
extern char	**environ;

/*
 * Some DOS data structures -- API, but not ABI-compatible.
 */
struct ftime {
	int	ft_year;
	int	ft_month;
	int	ft_day;
	int	ft_hour;
	int	ft_min;	
	int	ft_tsec;
};

struct date {
	int	da_year;
	char	da_mon;
	char	da_day;
};

struct time {
	unsigned char	ti_hour;
	unsigned char	ti_min;
	unsigned char	ti_sec;
	unsigned char	ti_hund;
};

struct dostime {
	unsigned char hour;
	unsigned char minute;
	unsigned char second;
	unsigned char hsecond;
};

struct ffblk {
	int		_ff_next;
	char		_ff_pattern[PATH_MAX];
	unsigned char	ff_attrib;
	unsigned short	ff_ftime;
	unsigned short	ff_fdate;
	unsigned long	ff_fsize;
	char		ff_name[PATH_MAX];
};

struct dfree {
	unsigned int	df_avail;	/* Number of available clusters. */
	unsigned int	df_total;	/* Total number of clusters. */
	unsigned int	df_bsec;	/* Bytes per sector. */
	unsigned int	df_sclus;	/* Sectors per cluster. */
};

struct SREGS {
	unsigned short es;
	unsigned short ds;
	unsigned short fs;
	unsigned short gs;
	unsigned short cs;
	unsigned short ss;
};

struct DWORDREGS {
	unsigned long edi;
	unsigned long esi;
	unsigned long ebp;
	unsigned long cflag;
	unsigned long ebx;
	unsigned long edx;
	unsigned long ecx;
	unsigned long eax;
	unsigned short eflags;
};

struct WORDREGS {
	unsigned short di, _upper_di;
	unsigned short si, _upper_si;
	unsigned short bp, _upper_bp;
	unsigned short cflag, _upper_cflag;
	unsigned short bx, _upper_bx;
	unsigned short dx, _upper_dx;
	unsigned short cx, _upper_cx;
	unsigned short ax, _upper_ax;
	unsigned short flags;
};

struct BYTEREGS {
	unsigned short di, _upper_di;
	unsigned short si, _upper_si;
	unsigned short bp, _upper_bp;
	unsigned long cflag;
	unsigned char bl;
	unsigned char bh;
	unsigned short _upper_bx;
	unsigned char dl;
	unsigned char dh;
	unsigned short _upper_dx;
	unsigned char cl;
	unsigned char ch;
	unsigned short _upper_cx;
	unsigned char al;
	unsigned char ah;
	unsigned short _upper_ax;
	unsigned short flags;
};

union REGS {
	struct DWORDREGS d;
	struct WORDREGS w;
	struct WORDREGS x;
	struct BYTEREGS h;
};

/*
 * MS-DOS definitions.
 */
#define	_S_IWRITE	S_IWUSR
#define	_S_IREAD	S_IRUSR

#define	O_BINARY	0

#define	MAXDRIVE	3
#define	MAXPATH		80
#define	MAXDIR		66
#define	MAXFILE		9
#define	MAXEXT		5

/*
 * XXXRW: Probably, these should be fcntl/open flags from UNIX?
 */
#define	SH_COMPAT	0x00000000
#define	SH_DENYRW	0x10000000
#define	SH_DENYWR	0x20000000
#define	SH_DENYRD	0x30000000
#define	SH_DENYNO	0x40000000

/*
 * Flag values returned by fnsplit().  No easy online definitions so these
 * are made up.
 */
#define	DRIVE		0x00000001
#define	DIRECTORY	0x00000002
#define	FILENAME	0x00000003
#define	EXTENSION	0x00000004
#define	WILDCARDS 	0x00000005

/*
 * Arguments to findfirst().  No easy online definitions, so these are made
 * up.
 */
#define	FA_RDONLY	0x00000001
#define	FA_HIDDEN	0x00000002
#define	FA_SYSTEM	0x00000004
#define	FA_LABEL	0x00000008
#define	FA_DIREC	0x00000010
#define	FA_ARCH		0x00000020

/*
 * Faux hardware, entirely non-functional.
 */
void		disable(void);
void		enable(void);
unsigned char	inportb(unsigned short port);
unsigned char	outportb(unsigned short port, unsigned char data);

/*
 * Faux hardware, somewhat functional.
 */
void	 geninterrupt(int intr_num);
void	*getvect(int intr_num);
int	 int86(int ivec, union REGS *in, union REGS *out);
int	 int86x(int ivec, union REGS *in, union REGS *out,
	    struct SREGS *seg);
void	 setvect(int intr_num, void (*intr)(void));

/*
 * DOS compatibility routines, largely functional.
 */
int	 _chmod(const char *filename, int pmode, int fauxarg);
int	 chsize(int fildes, long size);
void	 delay(int msec);
time_t	 dostounix(struct date *d, struct dostime *t);
int	 filelength(int fd);
int	 findfirst(const char *pathname, struct ffblk *ffblk, int attrib);
int	 findnext(struct ffblk *ffblk);
int	 fnsplit(const char *path, char *drive, char *dir, char *name,
	    char *ext);
int	 getcurdir(int drive, char *direc);
void	 getdate(struct date *date);
void	 getdfree(unsigned char drive, struct dfree *ptr);
int	 getftime(int fd, struct ftime *ftime);
int	 getdisk(void);
void	 gettime(struct time *time);
char	*searchpath(const char *file);
int	 setdisk(int drive);
int	 setftime(int fd, struct ftime *ftime);
void	 unixtodos(time_t time, struct date *d, struct time *t);

/*
 * DOS-esque routines, renamed to avoid conflicts.
 */
int	dos_chdir(const char *filename);
int	dos_mkdir(const char *filename);
int	dos_open(const char *path, int flags, ...);

/*
 * Administer the DOS emulation environment.
 */
void	dos_init(const char *logfile, const char *disk_vector[],
	    const char *dir);

#endif /* !_DOS_H_ */
