#ifndef __VISIBLE_H__
#define __VISIBLE_H__ 1

#include <math.h>
#include <errno.h>

#include "imptypes.h"
#include "internalfile.h"
#include "internal.h"

// The perms that IMP code calls are implemented by 'static inline' calls on code in internal.[hc]

static inline _imp_string _imp_SNL(void) {
  _imp_string SNL = {.charno = {1, '\n'} };
  return SNL;
}

static inline double _imp_PI(void) {
  return 3.141592653589793238462;
}

// #########################################################################################

// forward references:

static inline _imp_string _imp_TOSTRING(int C);
static inline unsigned char *_imp_CHARNO(_imp_string *str, int i);
static inline unsigned char *_imp_LENGTH(_imp_string *str);

static inline double _imp_FLOAT(double N); // might be wrong. might be for converting an int to a real.

static inline _imp_address _imp_ADDR(void *P);

static inline unsigned char *_imp_BYTE(_imp_address N);
static inline unsigned char *_imp_BYTEINTEGER(_imp_address N);

static inline short *_imp_SHORT(_imp_address N);
static inline short *_imp_SHORTINTEGER(_imp_address N);

static inline int *_imp_INTEGER(_imp_address N);

static inline long long int *_imp_LONG(_imp_address N);
static inline long long int *_imp_LONGINTEGER(_imp_address N);

//static inline long long *_imp_LONGLONG(_imp_address N);
//static inline long long *_imp_LONGLONGINTEGER(_imp_address N);

static inline long long int _imp_LENGTHENI(int I);

static inline float *_imp_REAL(_imp_address N);

static inline double *_imp_LONGREAL(_imp_address N);

static inline _imp_string *_imp_STRING(_imp_address N);

static inline void *_imp_RECORD(_imp_address N);

// These typeof codes will have to be kept in synch with perms.inc:
#define _imp_type_BYTEINTEGER  1
#define _imp_type_SHORTINTEGER 2
#define _imp_type_INTEGER      3
#define _imp_type_LONGINTEGER  4
#define _imp_type_REAL         5
#define _imp_type_LONGREAL     6
#define _imp_type_STRING       7
#define _imp_type_RECORD       8
#define _imp_type_BYTEINTEGERNAME  11
#define _imp_type_SHORTINTEGERNAME 12
#define _imp_type_INTEGERNAME      13
#define _imp_type_LONGINTEGERNAME  14
#define _imp_type_REALNAME         15
#define _imp_type_LONGREALNAME     16
#define _imp_type_STRINGNAME       17
#define _imp_type_RECORDNAME       18

static inline int                      _imp_typeof(_imp_NAME N);
#define _imp_TYPEOF(var) do {                                                                             \
  else if (__builtin_types_compatible_p(typeof(var), unsigned char)) return _imp_type_BYTEINTEGER;        \
  else if (__builtin_types_compatible_p(typeof(var), short int))     return _imp_type_SHORTINTEGER;       \
  else if (__builtin_types_compatible_p(typeof(var), int))           return _imp_type_INTEGER;            \
  else if (__builtin_types_compatible_p(typeof(var), long long int)) return _imp_type_LONGINTEGER;        \
  else if (__builtin_types_compatible_p(typeof(var), float))         return _imp_type_REAL;               \
  else if (__builtin_types_compatible_p(typeof(var), double))        return _imp_type_LONGREAL;           \
  else if (__builtin_types_compatible_p(typeof(var), _imp_string))   return _imp_type_STRING;             \
  else if (__builtin_types_compatible_p(typeof(var), _imp_NAME))     return _imp_typeof(var);             \
  else if (__builtin_types_compatible_p(typeof(var), unsigned char *)) return _imp_type_BYTEINTEGERNAME;  \
  else if (__builtin_types_compatible_p(typeof(var), short int *))     return _imp_type_SHORTINTEGERNAME; \
  else if (__builtin_types_compatible_p(typeof(var), int *))           return _imp_type_INTEGERNAME;      \
  else if (__builtin_types_compatible_p(typeof(var), long long int *)) return _imp_type_LONGINTEGERNAME;  \
  else if (__builtin_types_compatible_p(typeof(var), float *))         return _imp_type_REALNAME;         \
  else if (__builtin_types_compatible_p(typeof(var), double *))        return _imp_type_LONGREALNAME;     \
  else if (__builtin_types_compatible_p(typeof(var), _imp_string *))   return _imp_type_STRINGNAME;       \
  else if (__builtin_types_compatible_p(typeof(var), _imp_NAME *))     return _imp_typeof(*var);          \
  else { fprintf(stderr, "TYPEOF fails - cannot determine type of parameter\n"); exit(1); }               \
} while(0)

#define _imp_SIZEOF(var) do {                                                                             \
  else if (__builtin_types_compatible_p(typeof(var), unsigned char)) return sizeof(char);                 \
  else if (__builtin_types_compatible_p(typeof(var), short int))     return sizeof(short);                \
  else if (__builtin_types_compatible_p(typeof(var), int))           return sizeof(int);                  \
  else if (__builtin_types_compatible_p(typeof(var), long long int)) return sizeof(long long int);        \
  else if (__builtin_types_compatible_p(typeof(var), float))         return sizeof(float);                \
  else if (__builtin_types_compatible_p(typeof(var), double))        return sizeof(double);               \
  else if (__builtin_types_compatible_p(typeof(var), _imp_string))   return 256; /* TO DO */              \
  else if (__builtin_types_compatible_p(typeof(var), _imp_NAME))     return _imp_sizeof(var);             \
  else if (__builtin_types_compatible_p(typeof(var), unsigned char *)) return  sizeof(void *);            \
  else if (__builtin_types_compatible_p(typeof(var), short int *))     return  sizeof(void *);            \
  else if (__builtin_types_compatible_p(typeof(var), int *))           return  sizeof(void *);            \
  else if (__builtin_types_compatible_p(typeof(var), long long int *)) return  sizeof(void *);            \
  else if (__builtin_types_compatible_p(typeof(var), float *))         return  sizeof(void *);            \
  else if (__builtin_types_compatible_p(typeof(var), double *))        return  sizeof(void *);            \
  else if (__builtin_types_compatible_p(typeof(var), _imp_string *))   return  sizeof(void *);            \
  else if (__builtin_types_compatible_p(typeof(var), _imp_NAME *))     return _imp_sizeof(*var);          \
  else return sizeof(var);                                                                                \
} while(0)

static inline double                   _imp_ARCSIN(double ANGLE);
static inline double                   _imp_ARCCOS(double ANGLE);
static inline double                   _imp_ARCTAN(double X, double Y);
static inline double                   _imp_ARCTAN1(double ANGLE);
static inline double                   _imp_SIN(double ANGLE);
static inline double                   _imp_COS(double ANGLE);
static inline double                   _imp_TAN(double ANGLE);
static inline double                   _imp_FRACTION(double R);
static inline double                   _imp_FRACPT(double R);
static inline int                      _imp_IMOD(int I);

#ifdef NEVER

// This is why perms need to be output in C using private internal names such as _imp_imod(N) ...

// %integerfn IMOD(%integer n)
//  %result = |N|
// %end

// If a user program did the above, it would cause an infinite recusion!

#endif

/* Perms from the earliest Imp compiler (allimpc1):
SELECTINPUT SELECTOUTPUT NEWLINE SPACE SKIPSYMBOL RUNOUT NEWLINES
SPACES NEXTSYMBOL PRINTSYMBOL READSYMBOL READ WRITE NEWPAGE ADDR
ARCSIN INT INTPT FRACPT PRINT PRINTFL REAL INTEGER MOD ARCCOS SQRT
LOG SIN COS TAN EXP MAPRECORD BYTEINTEGER SHORTINTEGER RADIUS
ARCTAN PARITY PRINTSTRING NL LONGREAL PRINTCH READCH STRING

Unimplemented ones are:
runout (paper tape, can ignore!)
maprecord (probably old name for RECORD())
radius (sqrt(a^2+b^2)
parity

So... *might* want to implement RADIUS() and PARITY()???
*/

static inline double                   _imp_MOD(double R);
static inline int                      _imp_INT(double R);
static inline int                      _imp_INTPT(double R);
static inline long int                 _imp_LINT(double R);
static inline long int                 _imp_LINTPT(double R);
static inline int                      _imp_TRUNC(double R);
static inline int                      _imp_ROUND(double R);
static inline long long int            _imp_IEXP(int NUM, int POWER);
static inline double                   _imp_REXP(double NUM, double POWER);
static inline double                   _imp_LOG(double X);
static inline int                      _imp_REM(int P, int Q);
static inline double                   _imp_SQRT(double NUM);
static inline int                      _imp_ISQRT(int NUM);
static inline int                      _imp_MULDIV(int A, int B, int C);
static inline void                     _imp_PROMPT(_imp_string S);
static inline void                     _imp_READSYMBOL(int *P);
static inline void                     _imp_READCH(int *P);
static inline int                      _imp_NEXTSYMBOL(void);
static inline int                      _imp_NEXTCH(void);
static inline void                     _imp_SKIPSYMBOL(void);
static inline void                     _imp_PRINTSYMBOL(char SYM);
static inline void                     _imp_PRINTCH(char SYM);
static inline void                     _imp_PRINTSTRING(_imp_string S);
static inline void                     _imp_WRITE(int V, int P);        // IMPORTANT: See https://gtoal.com/imp77/reference-manual/IO-LIBRARY-EXPERIMENTS.{imp,txt}
static inline void                     _imp_READITEM(_imp_string *S);
static inline void                     _imp_READSTRING(_imp_string *S);
static inline void                     _imp_READTEXT(_imp_string *S, int DELIM);
static inline _imp_string              _imp_NEXTITEM(void);
static inline void                     _imp_READLINE(_imp_string *S);
static inline int                      _imp_INSTREAM(void);
static inline int                      _imp_OUTSTREAM(void);
static inline int                      _imp_INPUTSTREAM(void);
static inline int                      _imp_OUTPUTSTREAM(void);
static inline _imp_string              _imp_INPUTNAME(void);
static inline _imp_string              _imp_OUTPUTNAME(void);
static inline _imp_string              _imp_INFILENAME(void);
static inline _imp_string              _imp_OUTFILENAME(void);
static inline void                     _imp_SELECTINPUT(int N);
static inline void                     _imp_SELECTOUTPUT(int N);
static inline void                     _imp_OPENINPUT(int N, _imp_string FD);
static inline void                     _imp_OPENOUTPUT(int N, _imp_string FD);
static inline void                     _imp_OPENBINARYINPUT(int N, _imp_string FD);
static inline void                     _imp_OPENBINARYOUTPUT(int N, _imp_string FD);
static inline void                     _imp_DEFINEINPUT(int I, _imp_string SPEC);
static inline void                     _imp_DEFINEOUTPUT(int I, _imp_string SPEC);
static inline void                     _imp_ABANDONINPUT(void);
static inline void                     _imp_ABANDONOUTPUT(void);
static inline void                     _imp_CLOSESTREAM(int stream);
static inline void                     _imp_CLOSEINPUT(void);
static inline void                     _imp_CLOSEOUTPUT(void);
static inline void                     _imp_RESETINPUT(void);
static inline void                     _imp_RESETOUTPUT(void);
static inline void                     _imp_COMPLETEINPUT(void);
static inline void                     _imp_COMPLETEOUTPUT(void);
static inline void                     _imp_POSITIONINPUT(int P);
static inline void                     _imp_POSITIONOUTPUT(int P);
static inline void                     _imp_SETINPUT(int P);
static inline void                     _imp_SETOUTPUT(int P);
static inline void                     _imp_INPUTPOSITION(void);
static inline void                     _imp_OUTPUTPOSITION(void);
static inline int                      _imp_ENDOFINPUT(void);
static inline int                      _imp_INPOS(void);
static inline int                      _imp_OUTPOS(void);
static inline void                     _imp_SPACE(void);
static inline void                     _imp_SPACES(int N);
static inline void                     _imp_NEWPAGE(void);
static inline void                     _imp_NEWLINE(void);
static inline void                     _imp_NEWLINES(int N);
static inline void                     _imp_PRINT(double R, int BEFORE, int AFTER);        // IMPORTANT: See https://gtoal.com/imp77/reference-manual/IO-LIBRARY-EXPERIMENTS.{imp,txt}
static inline void                     _imp_PRINTFLOATING(double R, int A, int B);
static inline void                     _imp_PRINTFL(double R, int PLACES);
static inline void                     _imp_PRINTFHEX(double R);
static inline _imp_string              _imp_SUBSTRING(_imp_string S, int FROM, int TO);
static inline _imp_string              _imp_FROMSTRING(_imp_string S, int FROM, int TO);
static inline _imp_string              _imp_TRIM(_imp_string S, int MAX);
static inline _imp_string              _imp_TIME(void);
static inline _imp_string              _imp_DATE(void);
#ifdef WANT_EMAS_STYLE
static inline float                    _imp_CPUTIME(void);  // Result is seconds
#else
static inline int                      _imp_CPUTIME(void);  // Result is milliseconds
#endif
static inline _imp_string              _imp_CLIPARAM(void);

static inline int                      _imp_EVENT_(void);
static inline int                      _imp_SUBEVENT(void);
static inline int                      _imp_EVENTINFO(void);
static inline _imp_string              _imp_EVENTMESSAGE(void);
static inline _imp_string              _imp_ITOS(int I, int P);
static inline _imp_string              _imp_SSFMESSAGE(void);

// #########################################################################################

// Actual procedures:

static inline int _imp_ARGC(void) {
  return _imp_global_argc;
}

static inline _imp_string _imp_ARGV(int n) {
  return _imp_c2istr(_imp_global_argv[n]);
}


static inline _imp_string _imp_TOSTRING(int C) {
  _imp_string tmp;
  *_imp_LENGTH(&tmp) = 1; *_imp_CHARNO(&tmp, 1) = (C&255);
  return tmp; // Return whole string on the stack, not just a pointer.
}

static inline unsigned char *_imp_CHARNO(_imp_string *str, int i) {
  // TO DO: check 0 <= i <= LENGTH(str)  (worry about sizeof str later)
  return &str->charno[i];
}

static inline unsigned char *_imp_LENGTH(_imp_string *str) { return &str->length; }

static inline double _imp_FLOAT(double N) {
  return N; // if FLOAT() is passed an integer, C will promote it to double.
            // %real in imp is evaluated as double everywhere except when
            // assigned to a 4-byte memory location.
}

static inline _imp_address _imp_ADDR(void *P) {
  return (_imp_address)P;
}

//%record(*)%map NEW(%name v)  *** This is a tricky one and may need some work.
#define _imp_NEW(var) ((typeof(var))malloc(sizeof(*(var))))
//%routine DISPOSE(%name v)
#define _imp_DISPOSE(var) free(var)
  
// 8 bit
static inline unsigned char *_imp_BYTE(_imp_address N) {
  return (unsigned char *)N;
}

// 8 bit
static inline unsigned char *_imp_BYTEINTEGER(_imp_address N) {
  return (unsigned char *)N;
}

// 16 bit
static inline short int *_imp_SHORT(_imp_address N) {
  return (short int *)N;
}

// 16 bit
static inline short int *_imp_SHORTINTEGER(_imp_address N) {
  return (short int *)N;
}

// 32 bit
static inline int *_imp_INTEGER(_imp_address N) {
  // really a C 'long int' but a lot of hassle to change this everywhere
  // 
  return (int *)N;
}

// 64 bit
static inline long long int *_imp_LONG(_imp_address N) {
  return (long long int *)N;
}

// 64 bit
static inline long long int *_imp_LONGINTEGER(_imp_address N) {
  return (long long int *)N;
}

// 128 bit Doesn't exist in Imp77 yet.
//static inline long long *_imp_LONGLONG(_imp_address N) {
//  return (long long *)N;
//}

// 128 bit Doesn't exist in Imp77 yet.
//static inline long long *_imp_LONGLONGINTEGER(_imp_address N) {
//  return (long long *)N;
//}

// 64 bit
static inline long long int _imp_LENGTHENI(int I) { return (long long int) I; }

// 32 bit
static inline float *_imp_REAL(_imp_address N) {
  return (float *)N;
}

// 64 bit
static inline double *_imp_LONGREAL(_imp_address N) {
  return (double *)N;
}

// 128 bit
static inline long double *LONGLONGREAL(_imp_address N) {
  return (long double *)N;
}

static inline _imp_string *_imp_STRING(_imp_address N) {
  return (_imp_string *)N;
}

static inline void *_imp_RECORD(_imp_address N) {
  return (void *)N; // Needs compiler support with casting at the point of call...
}

/*
   Most math operations have multiple forms depending on the parameter/result type:

   float powf(float x, float y);
   double pow(double x, double y);
   long double powl(long double x, long double y);
 */

static inline double                   _imp_ARCSIN(double ANGLE) { return asin(ANGLE); }
static inline double                   _imp_ARCCOS(double ANGLE) { return acos(ANGLE); }
static inline double                   _imp_ARCTAN(double X, double Y) { return atan2(X, Y); }
static inline double                   _imp_ARCTAN1(double ANGLE) { return atan(ANGLE); }

static inline double                   _imp_SIN(double ANGLE) { return sin(ANGLE); }
static inline double                   _imp_COS(double ANGLE) { return cos(ANGLE); }
static inline double                   _imp_TAN(double ANGLE) { return tan(ANGLE); }

static inline double                   _imp_FRACTION(double R) { return R-_imp_TRUNC(R); }
static inline double                   _imp_FRACPT(double R) { return R-_imp_INTPT(R); }

static inline int                      _imp_IMOD(int I) { /*extern int abs(int j);*/ return abs(I); }
static inline double                   _imp_MOD(double R) { /*extern double fabs(double x);*/ return fabs(R); }

static inline int                      _imp_INT(double R) { return _imp_INTPT(R+0.5); }
static inline int                      _imp_INTPT(double R) { /*extern double floor(double x);*/ /*assert(floor(R) <= R);*/ return (int)floor(R); } // rounds *towards minus infinity*

static inline long int                 _imp_LINT(double R) { return _imp_LINTPT(R+0.5); }
static inline long int                 _imp_LINTPT(double R) { /*extern double floor(double x);*/ /*assert(floor(R) <= R);*/ return (long int)floor(R); }

static inline int                      _imp_TRUNC(double R) { /*extern double trunc(double x);*/ return (int)trunc(R); } // rounds *towards 0*
static inline int                      _imp_ROUND(double R) { return _imp_TRUNC(R < 0.0 ? R-0.5 : R+0.5); }

static inline long long int            _imp_IEXP(int NUM, int POWER) {
                                         int tot = 1, mul = POWER;
                                         while (mul-- > 0) tot *= NUM;
                                         return tot; // return (long)exp(NUM, POWER);
                                       }

static inline double                   _imp_REXP(double NUM, double POWER) {
                                         /*extern double pow(double x, double y);*/
                                         return POWER==2 ? NUM*NUM : pow(NUM,POWER);
                                       }

static inline double                   _imp_LOG(double X) { return log(X); }
static inline int                      _imp_REM(int P, int Q) { return P % Q; }
static inline double                   _imp_SQRT(double NUM) { /*extern double sqrt(double x);*/ return sqrt(NUM); }
static inline int                      _imp_ISQRT(int NUM) { /*extern double sqrt(double x);*/ return (int)sqrt(NUM); }
static inline int                      _imp_MULDIV(int A, int B, int C) { return (int) (((long long)A * (long long)B) / (long long)C); }

static inline void                     _imp_PROMPT(_imp_string S) { check_instream(__PRETTY_FUNCTION__); _imp_promptstr = S; }
static inline void                     _imp_READSYMBOL(int *P) { _imp_readsymbol(P); }
static inline void                     _imp_READCH(int *P) { _imp_readch(P); }
static inline int                      _imp_NEXTSYMBOL(void) { return _imp_nextsymbol(); }
static inline int                      _imp_NEXTCH(void) { return _imp_nextch(); }
static inline void                     _imp_SKIPSYMBOL(void) { _imp_skipsymbol(); }
static inline void                     _imp_PRINTSYMBOL(char SYM) { _imp_printsymbol(SYM); }
static inline void                     _imp_PRINTCH(char SYM) { _imp_printch(SYM); }
static inline void                     _imp_PRINTSTRING(_imp_string S) { _imp_printstring(S); }
static inline void                     _imp_WRITE(int V, int P) { _imp_write(V, P); }        // IMPORTANT: See https://gtoal.com/imp77/reference-manual/IO-LIBRARY-EXPERIMENTS.{imp,txt}

static inline void                     _imp_READITEM(_imp_string *S) { _imp_readitem(S);  }
static inline void                     _imp_READSTRING(_imp_string *S) { _imp_readstring(S); }
static inline void                     _imp_READTEXT(_imp_string *S, int DELIM) { _imp_readtext(S, DELIM); }
static inline _imp_string              _imp_NEXTITEM(void) { return _imp_nextitem(); }
static inline void                     _imp_READLINE(_imp_string *S) { _imp_readline(S); }

static inline void                     _imp_SETSTREAMS(void) {
  /* To do - not a serious implementation yet. */
  // Just enough to get layout.imp from the Dec10 running!
  _imp_OPENOUTPUT(2, _imp_str_literal("/dev/stdout"));
}

static inline int                      _imp_INSTREAM(void) { check_instream(__PRETTY_FUNCTION__); return _imp_InStream; }
static inline int                      _imp_OUTSTREAM(void) { check_outstream(__PRETTY_FUNCTION__); return _imp_OutStream; }
static inline int                      _imp_OUTDEV(void) { check_outstream(__PRETTY_FUNCTION__); return _imp_OutStream; }
static inline int                      _imp_INPUTSTREAM(void) { check_instream(__PRETTY_FUNCTION__); return _imp_InStream; }
static inline int                      _imp_OUTPUTSTREAM(void) { check_outstream(__PRETTY_FUNCTION__); return _imp_OutStream; }
static inline _imp_string              _imp_INPUTNAME(void) { check_instream(__PRETTY_FUNCTION__); return _imp_infile[_imp_InStream].fname; }
static inline _imp_string              _imp_OUTPUTNAME(void) { check_outstream(__PRETTY_FUNCTION__); return _imp_outfile[_imp_OutStream].fname; }
static inline _imp_string              _imp_INFILENAME(void) { check_instream(__PRETTY_FUNCTION__); return _imp_infile[_imp_InStream].fname; }
static inline _imp_string              _imp_OUTFILENAME(void) { check_outstream(__PRETTY_FUNCTION__); return _imp_outfile[_imp_OutStream].fname; }
static inline void                     _imp_SELECTINPUT(int N) { if (N < 0) return; _imp_InStream = N; _imp_INFILE = _imp_infile[N].f; check_instream(__PRETTY_FUNCTION__); }
static inline void                     _imp_SELECTOUTPUT(int N) { if (N < 0) return; _imp_OutStream = N; _imp_OUTFILE = _imp_outfile[N].f; check_outstream(__PRETTY_FUNCTION__); }
static inline void                     _imp_OPENINPUT(int N, _imp_string FD) { _imp_openinput(N, FD); }
static inline void                     _imp_OPENOUTPUT(int N, _imp_string FD) { _imp_openoutput(N, FD); }
static inline void                     _imp_OPENBINARYINPUT(int N, _imp_string FD) { _imp_openinput(N, FD); }
static inline void                     _imp_OPENBINARYOUTPUT(int N, _imp_string FD) { _imp_openoutput(N, FD); }
static inline void                     _imp_DEFINEINPUT(int I, _imp_string SPEC) { _imp_OPENINPUT(I, SPEC); }
static inline void                     _imp_DEFINEOUTPUT(int I, _imp_string SPEC) { _imp_OPENOUTPUT(I, SPEC); }
static inline void                     _imp_ABANDONINPUT(void) { _imp_abandoninput(); }
static inline void                     _imp_ABANDONOUTPUT(void) { _imp_abandonoutput(); }
static inline void                     _imp_CLOSESTREAM(int stream) { _imp_closestream(stream); } /* EMAS */
static inline void                     _imp_CLOSEINPUT(void) { _imp_closeinput(); }
static inline void                     _imp_CLOSEOUTPUT(void) { _imp_closeoutput(); }
static inline void                     _imp_RESETINPUT(void) { check_instream(__PRETTY_FUNCTION__); fseek(_imp_infile[_imp_InStream].f, 0L, SEEK_SET); }
static inline void                     _imp_RESETOUTPUT(void) { check_outstream(__PRETTY_FUNCTION__); }
static inline void                     _imp_COMPLETEINPUT(void) { check_instream(__PRETTY_FUNCTION__); }
static inline void                     _imp_COMPLETEOUTPUT(void) { check_outstream(__PRETTY_FUNCTION__); }

// seek/tell:
static inline void                     _imp_POSITIONINPUT(int P) { _imp_SETINPUT(P); }
static inline void                     _imp_POSITIONOUTPUT(int P) { _imp_SETOUTPUT(P); }
static inline void                     _imp_SETINPUT(int P) { check_instream(__PRETTY_FUNCTION__); fseek (_imp_INFILE, P, SEEK_SET); }
static inline void                     _imp_SETOUTPUT(int P) { check_outstream(__PRETTY_FUNCTION__); fseek (_imp_OUTFILE, P, SEEK_SET); }
static inline void                     _imp_INPUTPOSITION(void) { check_instream(__PRETTY_FUNCTION__); }  // TO DO: is this also 'inpos' or is it the ftell file offset?
static inline void                     _imp_OUTPUTPOSITION(void) { check_outstream(__PRETTY_FUNCTION__); }
static inline int                      _imp_ENDOFINPUT(void) { return 0; /*TO DO*/}

static inline int                      _imp_INPOS(void) { check_instream(__PRETTY_FUNCTION__); return _imp_infile[_imp_InStream].inpos; }
static inline int                      _imp_OUTPOS(void) { check_outstream(__PRETTY_FUNCTION__); return _imp_outfile[_imp_OutStream].outpos; }

static inline void                     _imp_SPACE(void) { _imp_space(); }
static inline void                     _imp_SPACES(int N) { _imp_spaces(N); }
static inline void                     _imp_NEWPAGE(void) { _imp_newpage(); }
static inline void                     _imp_NEWLINE(void) { _imp_newline(); }
static inline void                     _imp_NEWLINES(int N) { _imp_newlines(N); }
static inline void                     _imp_PRINT(double R, int BEFORE, int AFTER) { _imp_print(R, BEFORE, AFTER); }        // IMPORTANT: See https://gtoal.com/imp77/reference-manual/IO-LIBRARY-EXPERIMENTS.{imp,txt}
static inline void                     _imp_PRINTFLOATING(double R, int A, int B) { _imp_printfloating(R, A, B); }
static inline void                     _imp_PRINTFL(double R, int PLACES) { _imp_printfl(R, PLACES); }
static inline void                     _imp_PRINTFHEX(double R) { _imp_printfhex(R); }

// TOUPPER
// TOLOWER

static inline _imp_string              _imp_SUBSTRING(_imp_string S, int FROM, int TO) { return _imp_substring(S, FROM, TO); }
static inline _imp_string              _imp_FROMSTRING(_imp_string S, int FROM, int TO) { return _imp_substring(S, FROM, TO); }
static inline _imp_string              _imp_TRIM(_imp_string S, int MAX) { return _imp_trim(S, MAX); }

static inline _imp_string              _imp_TIME(void) { return _imp_time(); }
static inline _imp_string              _imp_DATE(void) { return _imp_date(); }
static inline int                      _imp_CPUTIME(void) { return _imp_cputime(); }

static inline _imp_string              _imp_CLIPARAM(void) { return _imp_cliparam(); }

// FREESTORE
static inline int                      _imp_FREESTORE(void) { return 0x8000; }  // made up value for old Imp15 programs. Could do a real number for modern linux.

static inline _imp_string              _imp_ITOS(int I, int P) { return _imp_itos(I, P); }
// there are some other calls like ITOS I think.  (Also check re ITOS2/ITOS)

// not to be confused with the EVENT_MESSAGE field.  This is specifically for native system calls that went wrong.
static inline _imp_string              _imp_SSFMESSAGE(void) { return _imp_c2istr(strerror(errno)); }

#endif // __VISIBLE_H__
