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

  Copyright (c) 1997 Novell, Inc.  All Rights Reserved.

  With respect to this file, Novell hereby grants to Developer a 
  royalty-free, non-exclusive license to include this sample code 
  and derivative binaries in its product. Novell grants to Developer 
  worldwide distribution rights to market, distribute or sell this 
  sample code file and derivative binaries as a component of 
  Developer's product(s).  Novell shall have no obligations to 
  Developer or Developer's customers with respect to this code.
  
  DISCLAIMER:
  
  Novell disclaims and excludes any and all express, implied, and 
  statutory warranties, including, without limitation, warranties 
  of good title, warranties against infringement, and the implied 
  warranties of merchantibility and fitness for a particular purpose.  
  Novell does not warrant that the software will satisfy customer's 
  requirements or that the licensed works are without defect or error 
  or that the operation of the software will be uninterrupted.  
  Novell makes no warranties respecting any technical services or 
  support tools provided under the agreement, and disclaims all other 
  warranties, including the implied warranties of merchantability and 
  fitness for a particular purpose. */

/**************************************************************************
  EXSBFUNC.C
***************************************************************************

  This example shows how to replace the byte NoMap, Scan, and Parse
  functions with user-defined handlers.  The handlers in this example
  are similar to the system default handlers, except they use curly
  braces instead of square brackets in the conversion.

  For example:
     Unmappable byte 0x81 is converted to the unicode sequence "{81}".
     The Scan/Parse functions will convert byte string "{2620}" to
     the single unicode character 0x2620.

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

#include <nunicode.h>
#include <nwlocale.h>
#include <stdio.h>
#include <assert.h>

static nint N_API MyNoMapByteFunc(    /* My unmappable byte handler     */
    pCONVERT convert,           /* Converter handle                     */
    punicode output,            /* Pointer to current output position   */
    nuint    outputLeft,        /* Space left in output buffer          */
    pnuint   outputUsed,        /* Space used in output buffer          */
    pnuint8  badInput,          /* Pointer to unmappable bytes          */
    nuint    badInputSize);     /* Size of unmappable input             */

static pnuint8 N_API MyScanByteFunc( /* My byte scanner function        */
    pCONVERT convert,           /* Converter handle                     */
    pnuint8  in,                /* Input to be scanned                  */
    nint     scanMax);        

static nint N_API MyParseByteFunc(   /* My byte parser function         */
    pCONVERT convert,           /* Converter handle                     */
    punicode output,            /* Buffer for Unicode output            */
    nuint    outputleft,        /* Space left in output buf, excl null  */
    pnuint   outputUsed,        /* Space used in output buffer          */
    pnuint8  input,             /* Buffer containing byte input         */
    pnuint   inputUsed);        /* Number of bytes of input used        */


void main(void)
{
   pCONVERT pconv;
   nint     icode;
   nuint    actualLen;
   nuint8   byteIn1[5] = { 'a', 'b', 'c', 0x81, 0 };    /* Test string */
   nuint8   byteIn2[]  = "xyz{2620}";
   unicode  uniOut[80];

   /* Load a byte/uni converter for the code page 1252, which contains
      some unmappable bytes.  Error checking not shown. */
   icode = NWUXLoadByteUnicodeConverter(1252, &pconv);

   icode = NWUXSetByteFunctions(pconv, MyNoMapByteFunc,
                                MyScanByteFunc, MyParseByteFunc);
   if (icode)
      printf("NWUXSetByteFunctions returned error 0x%04X\n",icode);

   /* Set the NoMapByte action to call our handler.  Leave the NoMapUni
      action unchanged.  The default ScanByte action already calls
      the handler so we don't need to call NWUXScanAction. */
   icode = NWUXSetNoMapAction(pconv, NWU_CALL_HANDLER,
                              NWU_UNCHANGED_ACTION);

   /* This conversion uses our NoMap handler to produce the unicode
      string "abc{81}". */
   icode = NWUXByteToUnicode(pconv, uniOut, 80, byteIn1, &actualLen);
   assert( icode == 0  &&  uniOut[3] == '{' && actualLen == 7);

   /* This conversion uses our Byte/Parse functions to produce the
      unicode string { 'x', 'y', 'z', 0x2620, 0 }  */
   icode = NWUXByteToUnicode(pconv, uniOut, 80, byteIn2, &actualLen);
   assert( icode == 0  &&  uniOut[3] == 0x2620 && actualLen == 4);

   NWUXUnloadConverter(pconv);
}


/*----------------------------------------------------------------------*/

/*
   User-defined unmappable byte handler.  The converter calls this routine
   when an unmappable byte is encountered during byte-to-uni conversion.
   This example converts an unmappable byte to a 4 character unicode
   sequence "{nn}".

   The amount of output generated by a single call to this function
   should not exceed 256 characters.

*/

static nint N_API MyNoMapByteFunc(    /* My unmappable byte handler     */
    pCONVERT convert,           /* Converter handle                     */
    punicode output,            /* Pointer to current output position   */
    nuint    outputLeft,        /* Space left in output buffer          */
    pnuint   outputUsed,        /* Space used in output buffer          */
    pnuint8  badInput,          /* Pointer to unmappable bytes          */
    nuint    badInputSize)      /* Size of unmappable input             */
{
    nint     ccode = 0;         /* Error code                           */
    nuint    i;                 /* Loop variable                        */

    /* Is there enough room to write our output? */
    if (outputLeft >= *outputUsed)
    {
        /*  We will use four Unicodes each bad byte. */
        *outputUsed = badInputSize * 4;

        /* Process each bad character separately. Convert to "{nn}" */
        for ( i = 0 ; i < badInputSize ; i++ )
        {
            *output++ = '{';
            *output++ =  ((badInput[i] & 0xF0) >>  4) + 0x0030;
            *output++ =  (badInput[i] & 0x0F) + 0x0030;
            *output++ = '}';
        }
    }
    else      /* It won't fit.  Don't write anything to output buffer. */
    {
        *outputUsed = 0;
        ccode = NWU_BUFFER_FULL;
    }
    return (ccode);

}


/*----------------------------------------------------------------------*/

/*
   User-defined byte scan function.  The converter calls this routine
   to scan an input byte string for special sequences.  If one is found
   return a pointer to the start of the sequence.

   This example scans for the special byte sequence "{nnnn}".
*/

static pnuint8 N_API MyScanByteFunc(pCONVERT convert, pnuint8  in,
                                    nint scanMax)
{
    /* scanMax is not used */
    scanMax = scanMax;

    /*
        Look for {nnnn}, where n are hex digits
    */
    while (*in)
    {
       if (in[0] == '{')            /* Got opening '{' ?                */
          if (NWisxdigit(in[1]))       /* Got 1st hex digit?            */
             if (NWisxdigit(in[2]))       /* Got 2nd hex digit?         */
                if (NWisxdigit(in[3]))       /* Got 3rd hex digit?      */
                   if (NWisxdigit(in[4]))       /* Got 4th hex digit?   */
                      if (in[5] == '}')            /* Got closing '}' ? */
                         break;                       /* Match!         */

        in++;     /* Try the next character */
    }

    /*
        Did we exit because we hit the end of the string?
    */
    if (*in == '\0')
        in = NULL;

    return (in);
}


/*----------------------------------------------------------------------*/

/*
   User-defined byte parse function.  The converter calls this routine
   to process a special sequence previously found by the scan function.

   This example converts the special byte sequence "{nnnn}" into a
   single unicode character.

   The amount of output generated by a single call to this function
   should not exceed 256 characters.
*/

/* Utility routine used by the parse function. */
static nint DigitValue(nuint8  c)
{
    nint    value;              /* Value of this hex digit              */
    if (c >= '0' && c <= '9')
        value = c - '0';
    else
        value = c - 'A' + 10;
    return (value);
}

static nint N_API MyParseByteFunc(   /* My byte parser function         */
    pCONVERT convert,           /* Converter handle                     */
    punicode output,            /* Buffer for Unicode output            */
    nuint    outputleft,        /* Space left in output buf, excl null  */
    pnuint   outputUsed,        /* Space used in output buffer          */
    pnuint8  input,             /* Buffer containing byte input         */
    pnuint   inputUsed)         /* Number of bytes of input used        */
{
    if (outputleft)
    {
        *output = DigitValue(input[1]) * 0x1000 +
                  DigitValue(input[2]) * 0x0100 +
                  DigitValue(input[3]) * 0x0010 +
                  DigitValue(input[4]);

        *outputUsed = 1;
        *inputUsed = 6;

        return (0);
    }

    else
       return(NWU_BUFFER_FULL);
} 
