/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = QPUTIL.C
 *
 * DESCRIPTIVE NAME = PM Print Queue Processor
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : Utility functions for PM Print Queue Processor
 *
 *
 * FUNCTIONS
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include "pmprint.h"

/****************************************************************************
 *
 * FUNCTION NAME = EnterSem
 *
 * DESCRIPTION   = Get access to per-process MUTEX semaphore
 *
 * INPUT         = None
 *
 * OUTPUT        = Caller has exclusive access to per-process data
 *
 * RETURN-NORMAL = None
 *
 *
 * RETURN-ERROR  = None
 *
 *
 ****************************************************************************/

VOID EnterSem( VOID )
{
    if (!fInitDone)
        Panic( "Spooler not initialized", "EnterSem", 0 );
    else
        DosRequestMutexSem(semPMPRINT, SEM_INDEFINITE_WAIT);
}

/****************************************************************************
 *
 * FUNCTION NAME = LeaveSem
 *
 * DESCRIPTION   = Release access to per-process MUTEX semaphore
 *
 * INPUT         = None
 *
 * OUTPUT        = Caller gives up exclusive access to per-process data
 *
 * RETURN-NORMAL = None
 *
 *
 * RETURN-ERROR  = None
 *
 *
 ****************************************************************************/
VOID LeaveSem( VOID )
{
      DosReleaseMutexSem(semPMPRINT);
}

/****************************************************************************
 *
 * FUNCTION NAME = ExitSem
 *
 * DESCRIPTION   = Terminate per-process MUTEX semaphore
 *
 * INPUT         = None
 *
 * OUTPUT        = Caller closes exclusive access semaphore
 *
 * RETURN-NORMAL = None
 *
 *
 * RETURN-ERROR  = None
 *
 *
 ****************************************************************************/

VOID ExitSem( VOID )
{
      DosCloseMutexSem(semPMPRINT);
}

/****************************************************************************
 *
 * FUNCTION NAME = AsciiToInt
 *
 * DESCRIPTION   = Convert ascii string to integer, handling whitespace
 *
 * INPUT         = psz   - string to convert to numeric value
 *
 * OUTPUT        = numeric value of string
 *
 * RETURN-NORMAL = None
 *
 *
 * RETURN-ERROR  = None
 *
 *
 ****************************************************************************/

USHORT AsciiToInt( PSZ psz )
{
    USHORT n;
    UCHAR c;
    BOOL bNegative = FALSE;
    BOOL bDigitSeen= FALSE;

    while (*psz == ' ')
        psz++;

    c = *psz;
    if (c == '-')
        bNegative = TRUE;
    else
    if (c != '+')
        c = 0;

    if (c)
        psz++;

    n = 0;
    while (c = *psz++) {
        c -= '0';
        if (c > 9)
            break;

        else {
            bDigitSeen = TRUE;
            n = (n*10) + c;
            }
        }

    if (bNegative)
        return( -n );
    else
        return( n );
}

/****************************************************************************
 *
 * FUNCTION NAME = ParseKeyData
 *
 * DESCRIPTION   = Parse string for a separator character and allocate
 *                 and build array of strings from it.
 *                 Each string is null-terminated
 *
 * INPUT         = pszKeyData  - string to parse
 *                 chSep       - character separating keyname/keyvalue pairs
 *                 cbKeyData   - length of pszKeyData
 *                 pTempKeyBuf - temp buffer to return keydata in
 *                               Might not fit all keydata
 *                 cbTempBuf   - size(in bytes) of pTempKeyBuf
 *
 * OUTPUT        = pointer to key data structure
 *                 This will match pTempKeyBuf if keydata fits in the buffer
 *                 else the pointer is to memory allocated, which must
 *                 be freed by the caller.
 *
 * RETURN-NORMAL = pKeyData
 *
 *
 * RETURN-ERROR  = NULL
 *
 * NOTE: This routine expects the string being passed in to NOT contain
 *       double byte character set(DBCS).
 *       To accept DBCS strings use DosGetDBCSEnv().
 *
 ****************************************************************************/

PKEYDATA ParseKeyData( PSZ pszKeyData, UCHAR chSep, USHORT cbKeyData,
                       PKEYDATA pTempKeyBuf, USHORT cbTempBuf )
{
    USHORT   cTokens;
    USHORT   cb;
    USHORT   i;
    PKEYDATA pResult;
    PSZ      pDst;
    PSZ      psz;

    cTokens = 0;
    cb = cbKeyData;
    if (psz = pszKeyData)
    {
        while (cb-- && *psz)
        {
            if (*psz == chSep)
                cTokens++;
            psz++ ;
        }

        if (psz[-1] != chSep)
            if (chSep != ';')
                cTokens++;
            else
                cTokens = 0;
    }

    if (cb || *psz || !cTokens)
        return( NULL );

    cb = sizeof( KEYDATA ) + (cTokens-1) * sizeof( PSZ ) + cbKeyData;
    if (cb > cbTempBuf)
    {
       /*
       ** Won't fit in given buffer so allocate a new one.
       ** Caller must free this buffer.
       */
       if (DosAllocMem( (PVOID)&pResult, cb, PAG_COMMIT|PAG_READ|PAG_WRITE))
       {
          return(NULL);
       }
    } else {
       pResult = pTempKeyBuf ;
    }

    pResult->cb = cb;
    pResult->cTokens = cTokens;
    pDst = (PSZ)pResult + (cb-cbKeyData);
    i = 0;

    while (cTokens--)
    {
       pResult->pTokens[ i ] = pDst;
       while (*pDst = *pszKeyData++) {
          if (*pDst != chSep)
          {
              pDst++ ;
          }
          else {
              *pDst = '\0';
              break;
              }
          }

       if (pResult->pTokens[ i ] == pDst)
           pResult->pTokens[ i ] = NULL;
       else
       {
           pDst++ ;
       }
       i++;
    }

    return( pResult );
}

/*
** EndStrcpy()
**
**  RETURNS: a pointer to the terminating '\0' of the newly copied
**           destination string.
**
*/
PSZ EndStrcpy( PSZ pszDest, PSZ pszSrc )
{
        strcpy( pszDest, pszSrc );
        return( (PSZ)(pszDest + SafeStrlen( pszDest )) );
}


/*
** SafeStrlen()
**
**  Same as strlen(), but is safe for NULL ptrs.
**
**  RETURNS:  Length of string, or 0 if string is NULL.
**
**  NOTE:  "safe" does not mean that this function will never GP fault.
*/
int SafeStrlen( PSZ psz )
{
        if ( psz == (PSZ)NULL )
                return( 0 );
        else
                return( strlen( psz ) );
}

/*
** SafeStrcpy()
**
** Same as strcpyf(), but is safe for NULL ptrs
**
** NOTE:  "safe" does not mean that this function will never GP fault.
**        It can fault if, for example, either the source or dest is
**        garbage, or if pszSrc is NULL, but PszDest points to data
**        which contains no '\0' before the end of the segment.
*/
PSZ SafeStrcpy( PSZ pszDest, PSZ pszSrc )
{
        if ( pszDest == (PSZ)NULL || pszSrc == (PSZ)NULL )
                return( pszDest );
        else
                return( strcpy( pszDest, pszSrc ) );
}

/****************************************************************************
 *
 * FUNCTION NAME = ExceptHandler
 *
 * DESCRIPTION   = PMPRINT's exception handling routine.
 *                 This takes care of thread exceptions while in PMPRINT.
 *
 * INPUT         = pReport     - exception report record(see bsexcpt.h)
 *                 pRegister   - our exception registration record,
 *                               which contains the longjmp buffer
 *                 pContext    - context record(see bsexcpt.h)
 *                 pv          - not used by our exception handler
 *
 * RETURN-NORMAL = returns to caller with XCPT_CONTINUE_SEARCH if we
 *                 don't handle the exception
 *
 *
 * RETURN-ERROR  = reset context to time of setjmp() call and return
 *                 exception number to caller of setjmp()
 *
 *
 ****************************************************************************/


ULONG _System ExceptHandler( PEXCEPTIONREPORTRECORD pReport,
                                 PEXCEPTIONREGISTRATIONRECORD pRegister,
                                 PCONTEXTRECORD pContext,
                                 PVOID pv )
{
  // handle interesting exceptions
  switch( pReport->ExceptionNum )
  {
     case XCPT_ACCESS_VIOLATION:
     case XCPT_INTEGER_DIVIDE_BY_ZERO:
     case XCPT_INTEGER_OVERFLOW:
     case XCPT_PROCESS_TERMINATE:
     case XCPT_ASYNC_PROCESS_TERMINATE:
       // return exception number to setjmp()
       longjmp( ((PREGREC)pRegister)->jmp,  pReport->ExceptionNum );
  }
  // not interested; system should continue search
  return XCPT_CONTINUE_SEARCH;
}
