/*-
 ***********************************************************************
 *
 * $Id: pad-common.c,v 1.11 2012/01/07 07:56:14 mavrik Exp $
 *
 ***********************************************************************
 *
 * Copyright 2002-2012 The WebJob Project, All Rights Reserved.
 *
 ***********************************************************************
 */
#include "pad-common.h"

/*-
 ***********************************************************************
 *
 * Global Variables.
 *
 ***********************************************************************
 */
extern PAD_CALL_TABLE gsCallTable[];
extern int giNCalls;
extern void *gpvProperties;

/*-
 ***********************************************************************
 *
 * PaDGetBaseName
 *
 ***********************************************************************
 */
char *
PaDGetBasename(char *pcPath)
{
  int                 i;

  for (i = strlen(pcPath) - 1; i >= 0; i--)
  {
#ifdef WIN32
    if (pcPath[i] == '/' || pcPath[i] == '\\')
#else
    if (pcPath[i] == '/')
#endif
    {
      break;
    }
  }
  return &pcPath[++i];
}


/*-
 ***********************************************************************
 *
 * PaDGetCallname
 *
 ***********************************************************************
 */
char *
PaDGetCallname(void (*pvCall)())
{
  static char         acName[PAD_CALL_NAME_SIZE] = "";
  int                 i;

  for (i = 0; i < giNCalls; i++)
  {
    if (gsCallTable[i].pvCall == pvCall)
    {
      return gsCallTable[i].acName;
    }
  }
  i = (sizeof(pvCall) << 1);
  sprintf(acName, "0x%*.*lx()", i, i, (unsigned long) pvCall);
  return acName;
}


/*-
 ***********************************************************************
 *
 * PaDGetEnvValue
 *
 ***********************************************************************
 */
char *
PaDGetEnvValue(char *pcName)
{
#ifdef WIN32
  char               *pcValue = NULL;
  DWORD               dwCount = 0;

#define PAD_MAX_ENV_SIZE 32767 /* Source = MSDN documentation for GetEnvironmentVariable() */
  pcValue = calloc(PAD_MAX_ENV_SIZE, 1);
  if (pcValue == NULL)
  {
    return NULL;
  }
  dwCount = GetEnvironmentVariable(TEXT(pcName), pcValue, PAD_MAX_ENV_SIZE);
  return (dwCount == 0 || dwCount > PAD_MAX_ENV_SIZE) ? NULL : pcValue;
#else
  return getenv(pcName);
#endif
}


/*-
 ***********************************************************************
 *
 * PaDGetMyHandle
 *
 ***********************************************************************
 */
FILE *
PaDGetMyHandle(char *pcMyName, char *pcError)
{
  void              (*pvCall)() = PAD_VOID_CALL PaDGetMyHandle;
  char               *pcFilename;
  FILE               *pFile;

  pcFilename = calloc(strlen(pcMyName) + strlen(".exe") + 1, 1);
  if (pcFilename == NULL)
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): Error='%s'", PaDGetCallname(pvCall), strerror(errno));
    return NULL;
  }
  sprintf(pcFilename, "%s", pcMyName);
  pFile = fopen(pcFilename, "rb");
  if (pFile == NULL)
  {
#ifdef CYGWIN
    sprintf(pcFilename, "%s.exe", pcFilename);
    pFile = fopen(pcFilename, "rb");
    if (pFile != NULL)
    {
      free(pcFilename);
      return pFile;
    }
#endif
    if (errno == ENOENT)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: fopen(): File='%s' Error='%s' Hint='Try the command again using my qualified path.'", PaDGetCallname(pvCall), pcFilename, strerror(errno));
    }
    else
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: fopen(): File='%s' Error='%s'", PaDGetCallname(pvCall), pcFilename, strerror(errno));
    }
    free(pcFilename);
    return NULL;
  }
  free(pcFilename);
  return pFile;
}


/*-
 ***********************************************************************
 *
 * PaDGetPropertiesReference
 *
 ***********************************************************************
 */
void *
PaDGetPropertiesReference(void)
{
  return gpvProperties;
}


/*-
 ***********************************************************************
 *
 * PaDLocateDelimiter
 *
 ***********************************************************************
 */
int
PaDLocateDelimiter(FILE *pFile, char *pcDelimiter, char *pcError)
{
  void              (*pvCall)() = PAD_VOID_CALL PaDLocateDelimiter;
  char                acData[PAD_READ_SIZE * 3];
  char               *pc;
  int                 iCount;
  int                 iDone;
  int                 iIndex;
  int                 iKeep;
  int                 iLength;
  int                 iOffset;

  iDone = iKeep = iOffset = 0;

  pc = &acData[PAD_READ_SIZE * 2];

  iLength = strlen(pcDelimiter);

  /*-
   *********************************************************************
   *
   * Locate delimiter.
   *
   *********************************************************************
   */
  while (!iDone && (iCount = fread(&acData[PAD_READ_SIZE * 2], 1, PAD_READ_SIZE, pFile)))
  {
    iCount += iKeep;
    for (iIndex = 0; iCount >= iLength; pc++, iIndex++, iCount--)
    {
      if (memcmp(pc, pcDelimiter, iLength) == 0)
      {
        iDone = 1;
        iIndex += iLength;
        break;
      }
    }
    iOffset += iIndex;
    if (!iDone)
    {
      iKeep = iLength - 1;
      memcpy(&acData[(PAD_READ_SIZE * 2) - iKeep], pc, iKeep);
      pc = &acData[(PAD_READ_SIZE * 2) - iKeep];
    }
  }
  if (ferror(pFile))
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: fread(): Error='%s'", PaDGetCallname(pvCall), strerror(errno));
    return ER;
  }
  if (!iDone)
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: Error='Missing PaD delimiter.'", PaDGetCallname(pvCall));
    return ER;
  }

  /*-
   *********************************************************************
   *
   * Seek past the delimiter.
   *
   *********************************************************************
   */
  if (fseek(pFile, iOffset, SEEK_SET) == -1)
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: fseek(): Error='%s'", PaDGetCallname(pvCall), strerror(errno));
    return ER;
  }

  return ER_OK;
}


/*-
 ***********************************************************************
 *
 * PaDNewDelimiter
 *
 ***********************************************************************
 */
char *
PaDNewDelimiter(char *pcTemplate, int iConvert, char *pcError)
{
  void              (*pvCall)() = PAD_VOID_CALL PaDNewDelimiter;
  char               *pc;
  char               *pcDelimiter;
  int                 i;
  int                 iLength;

  iLength = strlen(pcTemplate) + 2;
  pcDelimiter = calloc(iLength, 1);
  if (pcDelimiter == NULL)
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): Error='%s'", PaDGetCallname(pvCall), strerror(errno));
    return NULL;
  }
  for (i = 0, pc = pcTemplate, iLength -= 2; i < iLength; i++)
  {
    pcDelimiter[i] = (iConvert) ? (pc[i] == ' ') ? '_' : pc[i] : pc[i];
  }
  pcDelimiter[i++] = '\n';
  pcDelimiter[i] = 0;
  return pcDelimiter;
}


/*-
 ***********************************************************************
 *
 * PaDNewProperties
 *
 ***********************************************************************
 */
void *
PaDNewProperties(int iSize, char *pcError)
{
  void              (*pvCall)() = PAD_VOID_CALL PaDNewProperties;
  void               *pvProperties;

  pvProperties = (void *) calloc(iSize, 1);
  if (pvProperties == NULL)
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: %s", PaDGetCallname(pvCall), strerror(errno));
    return NULL;
  }
  return pvProperties;
}


/*-
 ***********************************************************************
 *
 * PaDReadWrite
 *
 ***********************************************************************
 */
int
PaDReadWrite(FILE *pFileFrom, FILE *pFileTo, char *pcError)
{
  void              (*pvCall)() = PAD_VOID_CALL PaDReadWrite;
  char                acData[PAD_READ_SIZE];
  int                 iNRead;
  int                 iNWritten;

  while ((iNRead = fread(acData, 1, PAD_READ_SIZE, pFileFrom)))
  {
    iNWritten = fwrite(acData, 1, iNRead, pFileTo);
    if (iNWritten != iNRead)
    {
      snprintf(pcError, MESSAGE_SIZE, "%s: fwrite(): Error='%s'", PaDGetCallname(pvCall), strerror(errno));
      return ER;
    }
  }
  if (ferror(pFileFrom))
  {
    snprintf(pcError, MESSAGE_SIZE, "%s: fread(): Error='%s'", PaDGetCallname(pvCall), strerror(errno));
    return ER;
  }
  return ER_OK;
}


/*-
 ***********************************************************************
 *
 * PaDSetPropertiesReference
 *
 ***********************************************************************
 */
void
PaDSetPropertiesReference(void *pvProperties)
{
  gpvProperties = pvProperties;
}
