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

  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. */

/**************************************************************************
  EXSUFUNC.C
***************************************************************************

  This example shows how to replace the unicode 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:
     The unmappable unicode character 0x2620 is converted to the byte
     sequence "{2620}".  The Scan/Parse functions will convert unicode
     string "{81}" to the single byte 0x81.

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

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

static nint N_API MyNoMapUniFunc(    /* My unmappable uni handler       */
   pCONVERT convert,           /* Converter handle                      */
   pnuint8  output,            /* Buffer for byte output                */
   nuint    outputLeft,        /* Space left in output buffer           */
   pnuint   outputUsed,        /* Space used in output buffer           */
   punicode badInput,          /* Input buffer                          */
   nuint    badInputSize);     /* Length of unmappable input            */

static punicode N_API MyScanUniFunc( /* My uni scanner function         */
   pCONVERT  convert,          /* Converter handle                      */
   punicode  in,               /* Input to be scanned                   */
   nint      scanMax);         /* Maximum characters to scan            */

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

void main(void)
{
   pCONVERT pconv;
   nint     icode;
   nuint    actualLen;
   unicode  uniIn1[5] = { 'a', 'b', 'c', 0x2620, 0 };    /* Test string */
   unicode  uniIn2[8] = { 'x', 'y', 'z', '{', '8', '1', '}', 0 };
   nuint8   byteOut[80];

   /* Load a byte/uni converter for the current codepage.
      Error checking not shown. */
   icode = NWUXLoadByteUnicodeConverter(0, &pconv);


   icode = NWUXSetUniFunctions(pconv, MyNoMapUniFunc,
                                MyScanUniFunc, MyParseUniFunc);
   if (icode)
      printf("NWUXSetUniFunctions returned error 0x%04X\n",icode);

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

   /* This conversion uses our NoMap handler to produce the byte
      string "abc{2620}". */
   icode = NWUXUnicodeToByte(pconv, byteOut, 80, uniIn1, &actualLen);
   assert( icode == 0  &&  strcmp(byteOut,"abc{2620}") == 0 &&
           actualLen == 9 );

   /* This conversion uses our Byte/Parse functions to produce the
      byte string { 'x', 'y', 'z', 0x81, 0 }  */
   icode = NWUXUnicodeToByte(pconv, byteOut, 80, uniIn2, &actualLen);
   assert( icode == 0  &&  byteOut[3] == 0x81 && actualLen == 4);

   NWUXUnloadConverter(pconv);
}

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

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

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

static nint N_API MyNoMapUniFunc(    /* My unmappable uni handler       */
   pCONVERT convert,           /* Converter handle                      */
   pnuint8  output,            /* Buffer for byte output                */
   nuint    outputLeft,        /* Space left in output buffer           */
   pnuint   outputUsed,        /* Space used in output buffer           */
   punicode badInput,          /* Input buffer                          */
   nuint    badInputSize)      /* Length 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 six bytes for each bad Unicode character. */
        *outputUsed = badInputSize * 6;

        /* Process each bad character separately. */
        for ( i = 0 ; i < badInputSize ; i++ )
        {
            *output++ = '{';
            *output++ = ( (badInput[i] & 0xF000) >> 12) + 0x0030;
            *output++ = ( (badInput[i] & 0x0F00) >>  8) + 0x0030;
            *output++ = ( (badInput[i] & 0x00F0) >>  4) + 0x0030;
            *output++ = (  badInput[i] & 0x000F       ) + 0x0030;
            *output++ = '}';
        }
    }

    else            /*  It won't fit.  Don't write anything to output. */
    {
        ccode = NWU_BUFFER_FULL;
        *outputUsed = 0;
    }

    return (ccode);
}


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

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

   This example scans for the special unicode sequence "{nn}".
*/

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

    /*
        Look for {nn}, 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 (in[3] == '}')            /* Got closing '}' ?       */
                   break;                       /* Match!               */

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

    /*
        Did we exit because we hit the end of the string?
    */
    if (*in == 0x0000)
        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(unicode  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 MyParseUniFunc(   /* My uni parser function           */
    pCONVERT convert,           /* Converter handle                     */
    pnuint8  output,            /* Buffer for byte output               */
    nuint    outputleft,        /* Space left in output buf, excl null  */
    pnuint   outputUsed,        /* Space used in output buffer          */
    punicode input,             /* Buffer containing unicode input      */
    pnuint   inputUsed)         /* Number of uni chars of input used    */
{
    if (outputleft)
    {
        *output = DigitValue(input[1]) * 0x0010 +
                  DigitValue(input[2]);

        *outputUsed = 1;
        *inputUsed = 4;

        return (0);
    }

    else
       return(NWU_BUFFER_FULL);

}

