/* OS/2 32-bit EA code, (c) 1992 Kai Uwe Rommel */

#define INCL_NOPM
#define INCL_DOS
#define INCL_DOSNLS
#include <os2.h>

#include <sys/types.h>
#include <stdlib.h>
#include <string.h>

void GetEAs(char *path, char **bufptr, unsigned *size)
{
  PDENA2 pDENA, pFound;
  EAOP2 eaop;
  PGEA2 pGEA;
  PGEA2LIST pGEAlist;
  PFEA2LIST pFEAlist;
  PVOID pEAblock;
  ULONG ulAttributes;
  ULONG nLength;
  ULONG nBlock;
  char szName[CCHMAXPATH];

  *size = 0;

  if ( _osmode == DOS_MODE )
    return;

  strcpy(szName, path);
  nLength = strlen(szName);
  if ( szName[nLength - 1] == '/' )
    szName[nLength - 1] = 0;

  nBlock = 65535;
  if ( (pDENA = alloca((size_t) nBlock)) == NULL )
    return;

  ulAttributes = -1;

  if ( DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, nBlock,
                        &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
    || ulAttributes == 0
    || (pGEAlist = alloca((size_t) nBlock)) == NULL )
    return;

  pGEA = pGEAlist -> list;
  pFound = pDENA;

  while ( ulAttributes-- )
  {
    pGEA -> cbName = pFound -> cbName;
    strcpy(pGEA -> szName, pFound -> szName);

    nLength = sizeof(GEA2) + strlen(pGEA -> szName);
    nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);

    pGEA -> oNextEntryOffset = ulAttributes ? nLength : 0;
    pGEA   = (PGEA2)  ((PCH) pGEA + nLength);

    pFound = (PDENA2) ((PCH) pFound + pFound -> oNextEntryOffset);
  }

  if ( pGEA == pGEAlist -> list )
    return;

  pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;

  pFEAlist = (PVOID) pDENA;  /* reuse buffer */
  pFEAlist -> cbList = nBlock;

  eaop.fpGEA2List = pGEAlist;
  eaop.fpFEA2List = pFEAlist;
  eaop.oError = 0;

  if ( DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
			(PBYTE) &eaop, sizeof(eaop)) )
    return;

  if ( (pEAblock = malloc(pFEAlist -> cbList)) == NULL )
    return;

  memcpy(pEAblock, pFEAlist, pFEAlist -> cbList);

  *bufptr = (char *) pEAblock;
  *size = pFEAlist -> cbList;
}

void SetEAs(char *path, char *eablock)
{
  EAOP2 eaop;
  USHORT nLength;
  char szName[CCHMAXPATH];

  if ( _osmode == DOS_MODE )
    return;

  strcpy(szName, path);
  nLength = strlen(szName);
  if (szName[nLength - 1] == '/')
    szName[nLength - 1] = 0;

  eaop.fpGEA2List = NULL;
  eaop.fpFEA2List = (PFEA2LIST) eablock;
  eaop.oError = 0;

  DosSetPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &eaop, sizeof(eaop), 0);
}

void CopyEAs(char *src_path, char *dst_path)
{
  char *eablock;
  unsigned easize;

  GetEAs(src_path, &eablock, &easize);

  if ( easize )
  {
    SetEAs(dst_path, eablock);
    free(eablock);
  }
}

int getfmode(char *name)
{
  FILESTATUS3 fs;
  return DosQueryPathInfo(name, 1, &fs, sizeof(fs)) ? -1 : fs.attrFile;
}

int setfmode(char *name, unsigned mode)
{
  FILESTATUS3 fs;
  if ( DosQueryPathInfo(name, 1, &fs, sizeof(fs)) )
    return -1;
  fs.attrFile = mode;
  return DosSetPathInfo(name, 1, (PBYTE) &fs, sizeof(fs), 0) ? -1 : 0;
}

char *modestring(unsigned mode)
{
  static char buf[8];

  buf[0] = (mode & FILE_ARCHIVED) ? 'a' : '-';
  buf[1] = (mode & FILE_HIDDEN)   ? 'h' : '-';
  buf[2] = (mode & FILE_SYSTEM)   ? 's' : '-';
  buf[3] = 0;

  return buf;
}

void UnixFileName(char *name)
{
  for ( ; *name; name++ )
    if ( *name == '\\' )
      *name = '/';
}

static unsigned char cUpperCase[256], cLowerCase[256];
static BOOL bInitialized;

static void InitNLS(void)
{
  unsigned nCnt, nU;
  COUNTRYCODE cc;

  bInitialized = TRUE;

  for ( nCnt = 0; nCnt < 256; nCnt++ )
    cUpperCase[nCnt] = cLowerCase[nCnt] = (unsigned char) nCnt;

  cc.country = cc.codepage = 0;
  DosMapCase(sizeof(cUpperCase), &cc, (PCHAR) cUpperCase);

  for ( nCnt = 0; nCnt < 256; nCnt++ )
  {
    nU = cUpperCase[nCnt];
    if (nU != nCnt && cLowerCase[nU] == (unsigned char) nU)
      cLowerCase[nU] = (unsigned char) nCnt;
  }

  for ( nCnt = 'A'; nCnt <= 'Z'; nCnt++ )
    cLowerCase[nCnt] = (unsigned char) (nCnt - 'A' + 'a');
}

int IsLower(int c)
{
  if ( !bInitialized )
    InitNLS();
  return (cUpperCase[c] != (unsigned char) c);
}

int IsUpper(int c)
{
  if ( !bInitialized )
    InitNLS();
  return (cLowerCase[c] != (unsigned char) c);
}

int ToLower(int c)
{
  if ( !bInitialized )
    InitNLS();
  return cLowerCase[(unsigned char) c];
}

int ToUpper(int c)
{
  if ( !bInitialized )
    InitNLS();
  return cUpperCase[(unsigned char) c];
}
