#ifndef P2C_H
#define P2C_H

#include <stdio.h>

# include <stddef.h>
# include <stdlib.h>

#include <string.h>

#ifdef __linux__
#include <unistd.h>
#endif


#include <ctype.h>
#include <math.h>
#include <setjmp.h>
#include <assert.h>
#include <stdbool.h>

# define log1p(X) log(1+(X))

typedef struct __p2c_jmp_buf {
    struct __p2c_jmp_buf *next;
    jmp_buf jbuf;
} __p2c_jmp_buf;


/* Warning: The following will not work if setjmp is used simultaneously.
   This also violates the ANSI restriction about using vars after longjmp,
   but a typical implementation of longjmp will get it right anyway. */
#ifndef FAKE_TRY
# define TRY(x)         do { __p2c_jmp_buf __try_jb;  \
			     __try_jb.next = __top_jb;  \
			     if (!setjmp((__top_jb = &__try_jb)->jbuf)) {
# define RECOVER(x)	__top_jb = __try_jb.next; } else {
# define RECOVER2(x,L)  __top_jb = __try_jb.next; } else {  \
			     if (0) { L: __top_jb = __try_jb.next; }
# define ENDTRY(x)      } } while (0) 
#else
# define TRY(x)         if (1) {
# define RECOVER(x)     } else do {
# define RECOVER2(x,L)  } else do { L: ;
# define ENDTRY(x)      } while (0)
#endif


#define SETBITS  32

typedef signed char schar;
typedef unsigned char uchar;

typedef struct {
    void* proc;
	void* link;
} _PROCEDURE;

#ifndef _FNSIZE
# define _FNSIZE  120
#endif


extern void    PASCAL_MAIN   (int, char **);
extern char    **P_argv;
extern int     P_argc;
extern short   P_escapecode;
extern int     P_ioresult;
extern __p2c_jmp_buf *__top_jb;
extern int     bigendian;

extern int      _OutMem     ();
extern int      _CaseCheck  ();
extern int      _NilCheck   ();
extern char   *_ShowEscape   (char *, int, int, char *);
extern int	_Escape      (int);
extern int	_EscIO       (int);

extern int      microsleep    (long);
extern long     ipow         (long, long);
extern char    *strsub       (char *, char *, int, int);
extern char    *strltrim     (char *);
extern char    *strrtrim     (char *);
extern char    *strrpt       (char *, char *, int);
extern char    *strpad       (char *, char *, int, int);
extern int      strpos2      (char *, char *, int);
extern void    strmove      (int len, char * s, int spos, char * d, int dpos);
extern int     strcicmp     (char * s1, char * s2);
extern long     memavail    ();
extern int      P_peek       (FILE *);
extern int      P_eof        (FILE *);
extern int      P_eoln       (FILE *);
extern void     P_readpaoc   (FILE *, char *, int);
extern void     P_readlnpaoc  (FILE *, char *, int);
extern long     P_maxpos     (FILE *);
extern char    *P_trimname   (char *, int);
extern long    *P_setunion   (long *, long *, long *);
extern long    *P_setint     (long *, long *, long *);
extern long    *P_setdiff    (long *, long *, long *);
extern long    *P_setxor     (long *, long *, long *);
extern int      P_inset      (unsigned, long *);
extern int      P_setequal   (long *, long *);
extern int      P_subset     (long *, long *);
extern long    *P_addset     (long *, unsigned);
extern long    *P_addsetr    (long *, unsigned, unsigned);
extern long    *P_remset     (long *, unsigned);
extern long    *P_setcpy     (long *, long *);
extern long    *P_expset     (long *, long);
extern long     P_packset    (long *);
extern int      P_getcmdline  (int l, int h, char *line);
extern void     TimeStamp    (int *Day, int *Month, int *Year,
				 int *Hour, int *Min, int *Sec);
extern void	P_sun_argv   (char *, int, int);

extern void     _local_p2c_init (void);


/* I/O error handling */
#define _CHKIO(cond,ior,val,def)  ((cond) ? P_ioresult=0,(val)  \
					  : P_ioresult=(ior),(def))
#define _SETIO(cond,ior)          (P_ioresult = (cond) ? 0 : (ior))

/* Following defines are suitable for the HP Pascal operating system */
#define FileNotFound     10
#define FileNotOpen      13
#define FileWriteError   38
#define BadInputFormat   14
#define EndOfFile        30

/* Creating temporary files */

/* File buffers */
#define FILEBUF(f,sc,type) sc int f##_BFLAGS;   \
			   sc type f##_BUFFER
#define FILEBUFNC(f,type)  int f##_BFLAGS;   \
			   type f##_BUFFER

#define RESETBUF(f,type)   (f##_BFLAGS = 1)
#define SETUPBUF(f,type)   (f##_BFLAGS = 0)

#define GETFBUF(f,type)    (*((f##_BFLAGS == 1 &&   \
			       ((f##_BFLAGS = 2),   \
				fread(&f##_BUFFER,  \
				      sizeof(type),1,(f)))),\
			      &f##_BUFFER))
#define AGETFBUF(f,type)   (f##_BFLAGS == 1 &&   \
			     ((f##_BFLAGS = 2),   \
			      fread(f,_BUFFER,  \
				    sizeof(type),1,(f)))),\
			    f,_BUFFER)

#define PUTFBUF(f,type,v)  (GETFBUF(f,type) = (v))
#define CPUTFBUF(f,v)      (PUTFBUF(f,char,v))
#define APUTFBUF(f,type,v) (memcpy(AGETFBUF(f,type), (v),  \
				   sizeof(f,_BUFFER)))

#define GET(f,type)        (f##_BFLAGS == 1 ?   \
			    fread(&f##_BUFFER,sizeof(type),1,(f)) :  \
			    (f##_BFLAGS = 1))

#define PUT(f,type)        (fwrite(&f##_BUFFER,sizeof(type),1,(f)),  \
			    (f##_BFLAGS = 0))
#define CPUT(f)            (PUT(f,char))

#define BUFEOF(f)	   (f##_BFLAGS != 2 && P_eof(f))
#define BUFFPOS(f)	   (ftell(f) - (f##_BFLAGS == 2))

typedef struct {
    FILE *f;
    FILEBUFNC(f,char);
    char name[_FNSIZE];
} _TEXT;

/* Memory allocation */
# define Malloc(n)  (malloc((n != 0) ? (n) : 1) ?: (void*)_OutMem())
#define Free(p)     (free((void*)(p)), (p)=NULL)

/* sign extension */
#define SEXT(x,n)   ((x) | -(((x) & (1L<<((n)-1))) << 1))

/* packed arrays */   /* BEWARE: these are untested! */
#define P_getbits_UB(a,i,n,L)   ((int)((a)[(i)>>((L)-(n))] >>   \
				       (((~(i))&((1<<((L)-(n)))-1)) << (n)) &  \
				       (1<<(1<<(n)))-1))

#define P_getbits_SB(a,i,n,L)   ((int)((a)[(i)>>((L)-(n))] <<   \
				       (16 - ((((~(i))&((1<<((L)-(n)))-1))+1) <<\
					      (n)) >> (16-(1<<(n))))))

#define P_putbits_UB(a,i,x,n,L) ((a)[(i)>>((L)-(n))] |=   \
				 (x) << (((~(i))&((1<<((L)-(n)))-1)) << (n)))

#define P_putbits_SB(a,i,x,n,L) ((a)[(i)>>((L)-(n))] |=   \
				 ((x) & (1<<(1<<(n)))-1) <<   \
				 (((~(i))&((1<<((L)-(n)))-1)) << (n)))

#define P_clrbits_B(a,i,n,L)    ((a)[(i)>>((L)-(n))] &=   \
				 ~( ((1<<(1<<(n)))-1) <<   \
				   (((~(i))&((1<<((L)-(n)))-1)) << (n))) )

/* small packed arrays */
#define P_getbits_US(v,i,n)     ((int)((v) >> ((i)<<(n)) & (1<<(1<<(n)))-1))
#define P_getbits_SS(v,i,n)     ((int)((long)(v) << (SETBITS - (((i)+1) << (n))) >> (SETBITS-(1<<(n)))))
#define P_putbits_US(v,i,x,n)   ((v) |= (x) << ((i) << (n)))
#define P_putbits_SS(v,i,x,n)   ((v) |= ((x) & (1<<(1<<(n)))-1) << ((i)<<(n)))
#define P_clrbits_S(v,i,n)      ((v) &= ~( ((1<<(1<<(n)))-1) << ((i)<<(n)) ))

#define P_max(a,b)   ((a) > (b) ? (a) : (b))
#define P_min(a,b)   ((a) < (b) ? (a) : (b))

/* Funcition for compiler warnings*/
#ifdef __GNUC__
#define DEPRECATED __attribute__((deprecated))
#else
/**
 * Deprecated functions
 *
 * Use this macro in front of a function declaration to say the function is deprecated.
 * The compiler may emit a warning every time the function is used
 */
#define DEPRECATED
#endif

#endif    /* P2C_H */

/* ifdefs for microsleep here */

#define BSDMICROSLEEP

#if !defined(L_cuserid)
#define L_cuserid 32
extern char * cuserid(char *);
#endif

/* End. */