/*
 * $Date: $
 * $Source: $
 * $Revision: $
 * $State: $
 *
 * $Log: $
 */

#ifndef _EMU_DEBUG_H
#define _EMU_DEBUG_H

#include "emu_defs.h"

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

struct debug_flags {
  unsigned char disk;		/* disk msgs,        "d" */
  unsigned char read;		/* disk read         "R" */
  unsigned char write;		/* disk write        "W" */
  unsigned char dos;		/* unparsed int 21h  "D" */
  unsigned char cdrom;          /* cdrom             "C" */
  unsigned char video;		/* video,            "v" */
  unsigned char X;		/* X support,        "X" */
  unsigned char keyb;		/* keyboard,         "k" */
  unsigned char io;		/* port I/O,         "i" */
  unsigned char serial;		/* serial,           "s" */
  unsigned char mouse;		/* mouse,            "m" */
  unsigned char defint;		/* default ints      "#" */
  unsigned char printer;	/* printer           "p" */
  unsigned char general;	/* general           "g" */
  unsigned char config;		/* configuration     "c" */
  unsigned char warning;	/* warning           "w" */
  unsigned char hardware;	/* hardware          "h" */
  unsigned char IPC;		/* IPC               "I" */
  unsigned char EMS;		/* EMS               "E" */
  unsigned char xms;		/* xms               "x" */
  unsigned char dpmi;		/* dpmi              "M" */
  unsigned char network;	/* IPX network       "n" */
  unsigned char pd;		/* Packet driver     "P" */
  unsigned char request;	/* PIC               "r" */
};

EXTERN struct debug_flags d INIT({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
				  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});

EXTERN FILE* dbg_fd INIT(NULL);

int error(const char *f,...);
int hard_error(const char *f, ...);

#define dbug_printf(f,a...)	ifprintf(2,f,##a)

#if CONFIG_DEBUG_PRINTF > 0

#define k_printf(f,a...) 	(d.keyb?ifprintf(d.keyb,f,##a):0)
#define h_printf(f,a...) 	ifprintf(d.hardware,f,##a)
#define v_printf(f,a...) 	ifprintf(d.video,f,##a)
#define X_printf(f,a...)        ifprintf(d.X,f,##a)
#define s_printf(f,a...) 	ifprintf(d.serial,f,##a)
#define p_printf(f,a...) 	ifprintf(d.printer,f,##a)
#define d_printf(f,a...) 	ifprintf(d.disk,f,##a)
#define i_printf(f,a...) 	ifprintf(d.io,f,##a)
#define R_printf(f,a...) 	ifprintf(d.read,f,##a)
#define W_printf(f,a...) 	ifprintf(d.write,f,##a)
#define C_printf(f,a...)        ifprintf(d.cdrom,f,##a)
#define g_printf(f,a...)	ifprintf(d.general,f,##a)
#define x_printf(f,a...)	ifprintf(d.xms,f,##a)
#define D_printf(f,a...)	ifprintf(d.dpmi,f,##a)
#define m_printf(f,a...)	ifprintf(d.mouse,f,##a)
#define I_printf(f,a...) 	ifprintf(d.IPC,f,##a)
#define E_printf(f,a...) 	ifprintf(d.EMS,f,##a)
#define c_printf(f,a...) 	ifprintf(d.config,f,##a)
#define e_printf(f,a...) 	ifprintf(1,f,##a)
#define n_printf(f,a...)        ifprintf(d.network,f,##a)	/* TRB */
#define n_printf(f,a...)        ifprintf(d.network,f,##a)  /* TRB     */
#define pd_printf(f,a...)       ifprintf(d.pd,f,##a)	   /* pktdrvr */
#define r_printf(f,a...)        ifprintf(d.request,f,##a)
#define warn(f,a...)     	ifprintf(d.warning,f,##a)

#else

#define k_printf(f,a...)
#define h_printf(f,a...)
#define v_printf(f,a...)
#define X_printf(f,a...)
#define s_printf(f,a...)
#define p_printf(f,a...)
#define d_printf(f,a...)
#define i_printf(f,a...)
#define R_printf(f,a...)
#define W_printf(f,a...)
#define C_printf(f,a...)
#define g_printf(f,a...)
#define x_printf(f,a...)
#define D_printf(f,a...)
#define m_printf(f,a...)
#define I_printf(f,a...)
#define E_printf(f,a...)
#define c_printf(f,a...)
#define e_printf(f,a...)
#define n_printf(f,a...)
#define pd_printf(f,a...)
#define r_printf(f,a...)
#define warn(f,a...)

#endif

/* this macro can be safely wrapped around a system call with no side
 * effects; using a feature of GCC, it returns the same value as the
 * function call argument inside.
 *
 * this is best used in places where the errors can't be sanely handled,
 * or are not expected...
 */
#define DOS_SYSCALL(sc) ({ int s_tmp = (int)sc; \
  if (s_tmp == -1) \
    error("SYSCALL ERROR: %d, *%s* in file %s, line %d: expr=\n\t%s\n", \
	  errno, strerror(errno), __FILE__, __LINE__, #sc); \
  s_tmp; })

#define RPT_SYSCALL(sc) (sc)

/* 2 arg open -- use creat for 3 arg open */
static inline int safe_open(const char *name, const int flags)
{
  int result;

  while (1) {
    result = open(name, flags);
    if (result == -1) {
      if (errno == EINTR)
	continue;
    }
    return result;
  }
}
 
extern int GetDebugFlagsHelper(char *);
extern int SetDebugFlagsHelper(char *);
extern int ifprintf(int, const char *,...) FORMAT(printf, 2, 3);

extern void show_regs(const char *, int);
extern void show_ints(int, int);

#endif /* _EMU_DEBUG_H */
