/* unix_os2.c */

#include "squid.h"

 #define INCL_DOS
 #include <os2.h>
 #include <ctype.h>
 #include <direct.h>
 #include <errno.h>

 #include <OS2WERR.H> // ToolKit
#include "os2_ErrCodes.h"
//DEBUG: section 99

/*
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include "UNIX_OS2.H"
#include "UNIX_OS2ps.H"
*/

/*
uid_t getuid(void)
{  return 1;
}
uid_t geteuid(void)
{  return 1;
}
int getegid (void)             / * gid_t getegid (void); * /
{   return 1;
}

struct group unix_os2_group_for_sex =
{ "users", 1, NULL};

struct group *getgrgid (gid_t gid)
{ return &unix_os2_group_for_sex;
}
struct group *getgrnam (__const__ char * grnam)
{ return &unix_os2_group_for_sex;
}

int setuid(gid_t uid)
{ return 0;
}
int setgid(gid_t uid)
{  return 0;
}

int waitpid (int pid, int *stat_loc, int options)
{  return 0;
}

struct passwd unix_os2passw;

struct passwd *getpwnam (__const__ char *passw)
{ return &unix_os2passw;
}

*/
char *StrEerror(int ierr);

char * GetOS2ErrorMessage(int ierr)
{ int i;
static char *Unknown = "Unknown";
  for(i=0; i< sizeof(OS2_ErrMessages) / sizeof(struct OS2_ErrMsg); i++)
  {  if(ierr == OS2_ErrMessages[i].ierrcode)
          return OS2_ErrMessages[i].msg;
  }
  return Unknown;
}

/* добавить процессу ReqCount файловых хендлов, возвращает текущее число хендлов (новое) */
int OS2SetRelMaxFH(int ReqCount)
{ ULONG    CurMaxFH;
  int rc;
  rc = DosSetRelMaxFH((PLONG)&ReqCount,     /* Using 0 here will return the       */
                           &CurMaxFH);    /* current number of file handles     */
  if(rc)
  {   debug(99, 0) ("OS2SetRelMaxFH: rc =%d, %s\n", rc, GetOS2ErrorMessage(rc));
  }
  return (int)CurMaxFH;
}



void setServerPriority(void)
{
/* change process priority to SERVER class */
    DosSetPriority (PRTYS_PROCESSTREE,
                       PRTYC_FOREGROUNDSERVER, 0L, 0L);
}

int statfs (const char *path, struct statfs *_stat)
{
    unsigned long fs_info[40] = {0};         /* File system info buffer     */
    int rc;
    int fs_num;

    if(*(path+1) == ':' && isalpha((unsigned char)*path) )
       fs_num = toupper(*path)-'A'+1;
    else
       fs_num = _getdrive();

    rc = DosQueryFSInfo(fs_num,                 /* Drive number */
                        FSIL_ALLOC,             /* Level 1 allocation info */
                        (void *)fs_info,
                        sizeof(fs_info));

    if (rc != 0) {
       if( rc == 15 )
           errno = ENOENT;
       else
           errno = EINVAL;
       return 1;
    }

    _stat->f_bsize = fs_info[1]*(unsigned short)fs_info[4];
    _stat->f_blocks = fs_info[2];
    _stat->f_bfree = fs_info[3];
    _stat->f_files = fs_info[2];
    _stat->f_ffree = fs_info[3];

    return 0;
}
/****************************************************/

int getpagesize (void)
{ ULONG   page_size;

  DosQuerySysInfo(QSV_PAGE_SIZE,         /* Request memory page size  */
                        QSV_PAGE_SIZE,
                        (PVOID)&page_size,
                        sizeof(page_size));
 return page_size;
}

/****************************************************/
// #define INCL_DOSFILEMGR          /* File Manager values */
// #define INCL_DOSERRORS           /* DOS Error values    */
// #include <os2.h>

int truncate (char *name, long length)
{
    HFILE  hfFileHandle   = 0L;     /* Handle for file being manipulated */
    ULONG  ulAction       = 0;      /* Action taken by DosOpen */
    APIRET rc             = 0;      /* Return code */
    int i;

    for(i=0;i<2;i++)
    {
         rc = DosOpen(name, &hfFileHandle, &ulAction, 4L,
                 FILE_ARCHIVED | FILE_NORMAL,
                 OPEN_ACTION_OPEN_IF_EXISTS,
                 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE  |
                 OPEN_ACCESS_READWRITE, 0L);

       if(rc == ERROR_TOO_MANY_OPEN_FILES && !i)   rc = OS2SetRelMaxFH(8);
       else break;
    }
    if (rc != 0) {
       debug(99, 0) ("truncate: Warning: DosOpen Error  %d, %s, file %s\n",
                       rc, GetOS2ErrorMessage(rc),name);
       return 1;
    }
    rc = DosSetFileSize (hfFileHandle, length);    /* Change file size */
    if (rc != 0) {
       debug(99, 0) ("truncate: Warning: DosSetFileSize Error  %d, %s, file %s\n",
                        rc, GetOS2ErrorMessage(rc), name);
       rc = DosClose(hfFileHandle);
       return 1;
    }
    rc = DosClose(hfFileHandle);
   return 0;
}


int fork(void)
{
//   printf("\nbeep fork\n\a");
   printf("\n\abeep fork\a\n");
 return 1;
}

int kill (int pid, int sig)
{
   printf("\n\abeep kill\n\a");
  return 0;
}

/* Create a pipe.  DST points to two int's which will receive the
   handles.  PIPESIZE is the size of the pipe.  Return errno. */

//int do_pipe (int *dst, ULONG pipesize)
int pipe (int *pn)
{
     HFILE    hfReadHandle;    /* Pointer to the read handle      */
     HFILE    hfWriteHandle;   /* Pointer to the write handle     */
     ULONG    ulPipeSize;      /* Pipe size                       */
     int      rc;            /* Return code                     */

     ulPipeSize = 4096;        /* Ask for 4KB of internal storage */
                               /* for the pipe                    */
/* DosCreatePipe creates an unnamed pipe. */

     rc = DosCreatePipe(&hfReadHandle,
                          &hfWriteHandle,
                          ulPipeSize);
     if(rc == ERROR_TOO_MANY_OPEN_FILES)
     {  rc = OS2SetRelMaxFH(8);
        rc = DosCreatePipe(&hfReadHandle, &hfWriteHandle, ulPipeSize);
     }
     if (rc != 0) {
         debug(99, 0) ("pipe: Create pipe error,rc=%d %s\n",rc, GetOS2ErrorMessage(rc) );

//         printf("DosCreatePipe error: return code = %ld",
//                rc);
         return -rc;
     }
     *pn     = hfReadHandle;
     *(pn+1) = hfWriteHandle;

  return 0;
}

/*
 * xstrerror() - sock_errno/strerror-like wrapper
 */
const char *
xstrerror_a(void)

{   int ierr;
    ierr = sock_errno();
    return xstrerror_i(ierr);
}

const char *
xstrerror_type(int type)
{
   if(type == FD_SOCKET)
      return xstrerror_a();
   return xstdio_strerror();
}


/* xstrerror(ierr) - sock_errno/strerror-like wrapper */
const char *
xstrerror_i(int ierr)
{   int i;
//!!not thread-safe
    static char xbstrerror_buf[BUFSIZ];
   if (ierr >= SOCEPERM && ierr <= SOCENOTEMPTY)
   {   for(i=0; i< sizeof(OS2TCPErrMessages) / sizeof(struct OS2_ErrMsg); i++)
       {  if(ierr == OS2TCPErrMessages[i].ierrcode)
           {  snprintf(xbstrerror_buf, BUFSIZ, "(%d) %s", ierr, OS2TCPErrMessages[i].msg);
              return xbstrerror_buf;
           }
       }
   }
   snprintf(xbstrerror_buf, BUFSIZ, "Unknown errcode: %i", ierr);
   return xbstrerror_buf;;
}

/*  xstdio_strerror() - strerror() wrapper */
const char *
xstdio_strerror(void)
{   static char xstrerror_buf[BUFSIZ];
    int fix_errno;
    fix_errno = errno;
    if (fix_errno < 0 || fix_errno >= EOS2ERR+1)
       snprintf(xstrerror_buf, BUFSIZ, "(%d) Unknown", fix_errno);
    else
    {
       if(EOS2ERR == fix_errno)
       {  int i,ierr;
          ierr = _doserrno;

          for(i=0; i< sizeof(OS2_ErrMessages) / sizeof(struct OS2_ErrMsg); i++)
           {  if(ierr == OS2_ErrMessages[i].ierrcode)
               {  snprintf(xstrerror_buf, BUFSIZ, "OS/2 error(%d) %s", ierr, OS2_ErrMessages[i].msg);
                  return xstrerror_buf;
               }
           }
           snprintf(xstrerror_buf, BUFSIZ, "Unknown errcode: %d OS/2 err=%d", fix_errno, ierr);
       } else
            snprintf(xstrerror_buf, BUFSIZ, "%s (%d)",  StdStrError(fix_errno),fix_errno);
    }
    return xstrerror_buf;
}

/* XXX strerror - work only with VAC installed */
char *StdStrError(int ierr)
{  int i;
static  char buf[128];
   for(i=0; i< sizeof(OS2_StdErrMessages) / sizeof(struct OS2_ErrMsg); i++)
   {  if(ierr == OS2_StdErrMessages[i].ierrcode)
            return   OS2_StdErrMessages[i].msg;
   }
   snprintf(buf,128,"There is no message for error %i",ierr);
   return &buf[0];
}

/*
EK replace for Unix's   int ignoreErrno(int ierrno)
 */
int ignoreErrno(int ierrno, int type)
{
   if(type == FD_SOCKET)
   {  ierrno  = sock_errno();
     switch (ierrno)
     {   case EINPROGRESS: /* SOCEINPROGRESS */
         case EWOULDBLOCK: /* SOCEWOULDBLOCK */
         case EALREADY:    /* SOCEALREADY */
         case SOCEINTR:    /* Unix EINTR !=  OS2 EINTR */
       return 1;
    default:
       return 0;
    }
   }
   switch (ierrno) {
    case EAGAIN:
    case EALREADY:
       return 1;
    default:
       return 0;
    }
    /* NOTREACHED */
}

int ignoreErrnoSocket(int i_errno)
{    switch (i_errno)
     {   case EINPROGRESS: /* SOCEINPROGRESS */
         case EWOULDBLOCK: /* SOCEWOULDBLOCK */
         case EALREADY:    /* SOCEALREADY */
         case SOCEINTR:    /* Unix EINTR !=  OS2 EINTR */
         case SOCECONNRESET: /* ????? */
       return 1;
    default:
       return 0;
    }
}

void SquidBeep(int freq, int t)
{  DosBeep(freq,t);
}

 /************************************************************************

 This example performs some memory allocations, then calls _heapchk to check the heap.

 ***********************************************************************/



 #include <stdlib.h>
 #include <stdio.h>
 #include <malloc.h>

 int CheckMem(void)
 {
    int  rc;

    if (_HEAPOK != (rc = _heapchk())) {
       switch(rc) {
          case _HEAPEMPTY:
             puts("The heap has not been initialized.\n");
             break;
          case _HEAPBADNODE:
             puts("A memory node is corrupted or the heap is damaged.\n");
             break;
          case _HEAPBADBEGIN:
             puts("The heap specified is not valid.\n");
             break;
       }
       exit(rc);
    }
    return 0;

    /****************************************************************************
       The output should be similar to :

       A memory node is corrupted or the heap is damaged.
    ****************************************************************************/
 }



