#define  INCL_DOSERRORS

#include <os2.h>
#include "bdcalls.h"
#include "bdatt.h"
#include "csd.h"
/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/*  SUBROUTINE NAME:    NLSSHAPEBIDISRTING                                   */
/*                                                                           */
/*  DESCRIPTIVE NAME:   Block shaping                                        */
/*                                                                           */
/*  COPYRIGHT:  (c) IBM Corp. 1989.                                          */
/*                                                                           */
/*  FUNCTION : This function calls the block_interface function several times*/
/*             to perform shaping of characters in a buffer of known length  */
/*                                                                           */
/*  ENTRY POINT:  NlsShapeBidiString                                         */
/*      LINKAGE:  CALL FAR (dynamic link API)                                */
/*                                                                           */
/*  INPUT: (BidiAtts, Reserved, @Source, @Target, Length, Increment )        */
/*         BidiAtts   DWORD   - BidiAttributes                               */
/*         Reserved   DWORD   - Reserved should equal to zero                */
/*         Source     @CHAR   - Pointer to the source buffer                 */
/*         Target     @CHAR   - Pointer to the target buffer                 */
/*         Increment  DWORD   - Increment step                               */
/*         Length     DWORD   - Length of the source and the target buffers  */
/*                                                                           */
/*  EXIT-NORMAL: RC=0                                                        */
/*                                                                           */
/*  EXIT-ERROR:                                                              */
/*         ERROR_BIDI_INVALID_ORIENTATION   - Invalid orientation value.     */
/*         ERROR_BIDI_INVALID_RESERVED      - Effect is not equal to zero    */
/*         ERROR_BIDI_INVALID_CSD           - Invalid csd value              */
/*         ERROR_BIDI_INVALID_LENGTH        - Length is equal to zero        */
/*         ERROR_BIDI_INVALID_INCREMENT     - Invalid increment value        */
/*         ERROR_BIDI_INVALID_COMBINATION   - The length is not a multiple   */
/*                                            of the increment.              */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:                                                 */
/*                                                                           */
/*        DWORD  error       - Returned error                                */
/*        DWORD  orient      - To store the orientation byte of the BidiAtts */
/*        DWORD  csd         - To store the csd byte of the BidiAtts         */
/*        DWORD  handle      - To be initialized with the state 'B'          */
/*        DWORD  n           - Dummy counter for the main buffer             */
/*        DWORD  src_offset  - To hold the offset part of the source pointer */
/*        DWORD  trg_offset  - To hold the offset part of the target pointer */
/*                                                                           */
/*        DWORD  firstsucc   - not used                                      */
/*                                                                           */
/*        DWORD  curr_char   - represents a blank                            */
/*                                                                           */
/*    GLOBAL DATA DEFINITION: NONE                                           */
/*                                                                           */
/*    ROUTINES:  block_interface()                                           */
/*               deshape()                                                   */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/

extern USHORT far pascal _loadds NlsShapeBidiString
             (ULONG BidiAtts, ULONG Reserved, PCHAR Source,
              PCHAR Target, ULONG Length, ULONG Increment)
{
 USHORT                   error = 0;
 unsigned long            orient,
                             /* to store the orientation byte in BidiAtts    */

                          csd,
                             /* to store the csd byte of BIDI Attributes.    */

                          n, /* dummy counter.                               */


                          src_offset,
                             /*to hold the offset value of the source pointer*/

                          trg_offset,
                             /*to hold the offset value of the target pointer*/

                          curr_char = BLANK_CH,
                             /* represents a blank                           */

                          firstsucc;
                             /* not used                                     */


char                      handle=BGN_STATE;
                             /*this variable holds the state of the character*/

 if(Reserved!=0)               /* check on the reserved value                  */
   {
      error=ERROR_BIDI_INVALID_RESERVED;
      return(error);
   }

 if( Increment==0 )
                             /* check on the invalid increment               */
   {
     error=ERROR_BIDI_INVALID_INCREMENT;
     return(error);
   }

 if( Length==0 )
                             /* if the length is zero                        */
   {
      error=ERROR_BIDI_INVALID_LENGTH;
      return(error);
  }

 if( (Length%Increment!=0) || (Increment>Length) )
                             /* if the length is not a multiple of the       */
                             /* increment or increment is greater than the   */
                             /* length, then error bad length                */
   {
      error=ERROR_BIDI_INVALID_COMBINATION;
      return(error);
  }
 csd=BidiAtts & 0x00ff;      /* bit ANDing to get the CSD value              */

 orient=(BidiAtts>>16) & 0x00ff;
                             /* bit ANDing to get the orientation            */

 switch ((int)csd)           /* check the value of the csd byte in BidiAtts  */
  {
    case 0: case 1: case 16: case 17 : case 18 : case 19 : case 20 :
    break;
    default:
      error = ERROR_BIDI_INVALID_CSD;
      return(error);
    break;
  }

 if(orient>1)                /* check on the orientation value should be     */
                             /* zero or one else there is an error           */
  {
   error= ERROR_BIDI_INVALID_ORIENTATION;
   return(error);
  }

 if( (((int)BidiAtts & 0x00ff)==1) && (Source==Target) )
                             /* if the csd value indicates pass through      */
                             /* i.e we are going to copy source into target  */
                             /* but since they are equal the function        */
                             /* returns                                      */
   return(error);

 switch((int)orient)
   {
    case 0:                  /* case of orientation is left to right         */
      n=Length-Increment;    /* initialize 'n' with where we start to loop   */

      while( n>=0 )
                             /* Loop on the source buffer for a number of    */
                             /* times equal to the length of the buffer and  */
                             /* and each time call the block_interface       */
                             /* function. It will call the shaping routines  */
                             /* to shape the character according to its two  */
                             /* preceding shaped characters.                 */
                             /* This loop ends at n==0.                      */
       {
         block_interface (&error, Length, &n, Source, Target, csd, orient,
                              Increment, &handle, BidiAtts);
       /* this modification is added to fix the bug of deshaping lam alef */
       /* located one character before the end of the buffer   4-2-91 */
         if (n==0)
             break;
         n-=Increment;
       }

                             /* This call is done to process the last element*/
                             /* in the buffer                                */
      if( (csd==0) && (Target[0] != (CHAR)YEH_HAMZA_CH) )

         shape_input(&handle,(PUCHAR)&curr_char,
                     (PUCHAR) &Target[0], (PUCHAR)&Target[Increment],
                     (PUCHAR)&firstsucc);
                             /* This call is done in case of csd =on to have */
                             /* the last element in the buffer in final shape*/
                             /* form assuming a succeeding blank character   */


    break;
    case 1:                  /* orientation is right to left                 */
      n=0;

      while( n<Length)
        {
          block_interface (&error, Length, &n, Source, Target, csd, orient,
                             Increment, &handle, BidiAtts);
           n+=Increment;
        }

      if( (csd==0) && (Target[Length-Increment] != (CHAR)YEH_HAMZA_CH) )

         shape_input(&handle,(PUCHAR)&curr_char,
                     (PUCHAR)&Target[Length-Increment],
                     (PUCHAR)&Target[Length-2*Increment], (PUCHAR)&firstsucc);
                             /* This call is done in case of csd =on to have */
                             /* the last element in the buffer in final shape*/
                             /* form assuming a succeeding blank character   */

    break;
    }
    return(error);
 }
/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/*  SUBROUTINE NAME:    BLOCK_INTERFACE                                      */
/*                                                                           */
/*  DESCRIPTIVE NAME:   This is the interface to call the shaping routine    */
/*                                                                           */
/*  FUNCTION : This function parses the csd value to determine whether to    */
/*             call the shape_input function to perform character shaping    */
/*             or to call the pre_deshape function to deshape the source     */
/*             buffer. It then copies it to the target buffer of the same    */
/*             length.                                                       */
/*                                                                           */
/*  ENTRY POINT:  block_interface                                            */
/*      LINKAGE:  CALL NEAR (from NlsShapeBidiString)                        */
/*                                                                           */
/*  INPUT: (error,length,offset,@source,@target,csd,orient,increment,        */
/*          @CsdHandle,BidiAtts)                                             */
/*         error      WORD    - Returned value                               */
/*         Length     DWORD   - Length of the source and the target buffers  */
/*         offset     @OTHER  - Pointer to the offset of the current chracter*/
/*                              in the source and target buffer.             */
/*         Source     @OTHER  - Pointer to the source buffer                 */
/*         Target     @OTHER  - Pointer to the target buffer                 */
/*         csd        DWORD   - The value of the csd byte in the BidiAtts    */
/*         orient     DWORD   - the orientation value                        */
/*         Increment  DWORD   - Increment step                               */
/*         CsdHandle  @OTHER  - Represent the state of the character         */
/*         BidiAtts   DWORD   - BidiAttributes                               */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURNED ERROR                                           */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:                                                 */
/*                                                                           */
/*       CHAR    firstsucc    - To hold the first succeeding char (not used) */
/*       CHAR    current      - Intermediate variable to hold the current    */
/*                              character                                    */
/*       CHAR    blank        - Represents the character blank               */
/*       DWORD   j            - To hold the offset parameter while copying   */
/*                              the characters skiped by the increment step  */
/*       DWORD   i            - Dummy counter for looping                    */
/*       DWORD   rc           - To hold the returned code from the function  */
/*                              pre_deshape.                                 */
/*                                                                           */
/*    GLOBAL DATA DEFINITION: NONE                                           */
/*                                                                           */
/*    ROUTINES:  shape_input()   - Called when shaping is required           */
/*               pre_deshape()   - Called when deshaping is required         */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/

void block_interface (USHORT * error, unsigned long length,
      unsigned long * offset, char far * source, char far  * target,
      unsigned long csd, unsigned long orient, unsigned long increment,
      unsigned char * CsdHandle, unsigned long BidiAtts)
{
char         current,        /* to hold the character to be shaped           */

             blank=0x20,

             firstsucc;      /* reserved not used                            */

unsigned long          j,    /* to hold the offset parameter while copying   */
                             /* the characters skiped by the increment step  */

                       i,    /* dummy counter for looping                    */

                       rc=0; /* to hold the returned code from the function  */
                             /* pre_deshape.                                 */


     if(orient==1)           /* orientation is right to left                 */
       {
         switch((int)csd)
          {
            case 0x00:       /* case of csd on.                                  */

               current=source[*offset];
                             /* Copy the current character from source.      */
                             /* The current character is the character       */
                             /* pointed to by the offset in the source or    */
                             /* target buffer.                               */
               if(*offset==0)
                             /* Due to boundary limitation, there is no      */
                             /* preceding character.                         */
                             /* The current character is shaped assuming     */
                             /* that the preceding characters are blank      */
                 {
                    shape_input(CsdHandle,&current,&blank,
                                        &blank,&firstsucc);
                             /* Call the shape routine giving it the current */
                             /* character and the two preceding characters   */
                             /* are assumed blanks.                          */
                  }

                if(*offset==increment)
                             /* This is the case when we read the second     */
                             /* character, it has one preceding character.   */
                             /* The character is shaped assuming that the    */
                             /* second preceding character is blank          */
                  {
                     shape_input(CsdHandle,&current,
                            &target[*offset-increment], &blank,&firstsucc);

                             /* In block shape the preceding character must  */
                             /* be shaped. As a result, we read any preceding*/
                             /* characters from the target and not the source*/
                   }

                if (*offset>=2*increment)
                   {
                             /* This is the general case where we have       */
                             /* the current character and its two preceding  */
                             /* characters                                   */
                     shape_input(CsdHandle,&current,
                       &target[*offset-increment], &target[*offset-2*increment],
                       &firstsucc);
                   }

                target[*offset]=current;
                             /* Copy the current character into target at the*/
                             /* offset position                              */

                if ( (source!=target) && ( increment > 1 ) )
                             /* Check if we need to write the characters     */
                             /* skipped due to the increment step            */

                 for (i=0,j=*offset; i<increment-1 ;i++,j++ )
                     target[j+1]=source[j+1];
                             /* write the characters skipped between         */
                             /* two increment steps                          */

             break;
             case 0x01 :     /* case of Passthru                             */

                target[*offset]=source[*offset];
                             /* copy the character from source into target   */

                if ( (source!=target) && ( increment > 1 ) )
                             /* Check if we need to write the characters     */
                             /* skipped due to the increment step            */
                 for (i=0,j=*offset; i<increment-1 ;i++,j++ )
                     target[j+1]=source[j+1];
                             /* write the characters skipped between         */
                             /* two increment steps                          */
             break;
             case 0x10 :     /* We put all these cases together because      */
             case 0x11 :     /* the deshape function ..that will be called   */
             case 0x12 :     /* later will take the responsibility to        */
             case 0x13 :     /* differentiate between base,initial,middle,   */
             case 0x14 :     /* final and isolated shapes.                   */

                rc=pre_deshape (BidiAtts,source,target,*offset, length, *offset,
                                length,error,increment);

                             /* This function handles deshaping of the       */
                             /* character to base,middle, final, initial Or  */
                             /* isolated shapes according to the Bidi        */
                             /* attributes passed.                           */
                             /* It returns a return code in case of          */
                             /* characters that are deshaped into two        */
                             /* characters i.e the succeeding character is   */
                             /* changed too. These characters are:           */
                             /* all LAMALEF characters with                  */
                             /* Bidi Attributes = base and the YEH HAMZA     */
                             /* with attributes = final or isolated shapes   */

                if ( (source!=target) && ( increment > 1 ) )
                             /* Check if we need to write the characters     */
                             /* skipped due to the increment step            */
                  {
                    for (i=0,j=*offset; i<increment-1 ;i++,j++ )
                        target[j+1]=source[j+1];
                             /* write the characters skipped between         */
                             /* two increment steps                          */
                  }

                if(rc==INC_ONE_MORE_TIME)
                             /* If the return code indicates the case of a   */
                             /* character deshaped into two characters then  */
                             /* we have to increment the offset by one step  */
                             /* to skip the succeeding character which is    */
                             /* already changed to its correct shape         */
                  {
                    *offset+=increment;
                    if ( (source!=target) && ( increment > 1 ) )
                             /* Check if we need to write the characters     */
                             /* skipped due to the increment step            */
                        for (i=0,j=*offset; i<increment-1 ;i++,j++ )
                              target[j+1]=source[j+1];
                 }
              break;
          }                  /* end switch of right orientation              */
       }                     /* end if of right orientation                  */

   if (orient==0)            /* case of orientation is left to right         */
     {
       switch ((int)csd)
         {
           case 0x00:        /* case of csd on.                              */

             current=source[*offset];
                             /* read the character  from source              */

             if(*offset==length-increment )
               {             /* case of no preceding characters              */
                  shape_input(CsdHandle,&current,&blank,
                                       &blank,&firstsucc);
               }

             if(*offset == (length-2*increment) )
               {             /* case of only one preceding character         */
                 shape_input(CsdHandle,&current,
                        &target[*offset+increment], &blank,&firstsucc);
               }

             if(*offset+2*increment<=length-increment)
               {             /* case of current with two preceding characters*/
                 shape_input(CsdHandle,&current,
                   &target[*offset+increment], &target[*offset+2*increment],
                     &firstsucc);
               }

             target[*offset]=current;

             if ( (source!=target) && ( increment > 1 ) )
               for (i=0,j=*offset; i<increment-1 ;i++,j++ )
                  target[j+1]=source[j+1];

           break;
           case 0x01 :       /* case of Passthru                             */

              target[*offset]=source[*offset];
              if ( (source!=target) && ( increment > 1 ) )
                for (i=0,j=*offset; i<increment-1 ;i++,j++ )
                   target[j+1]=source[j+1];
           break;

           case 0x10 :       /* case of base shape                           */
           case 0x11 :       /* case of initial shapes                       */
           case 0x12 :       /* case of middle shapes                        */
           case 0x13 :       /* case of final shapes                         */
           case 0x14 :       /* case of isolated shapes                      */
             rc=pre_deshape (BidiAtts,source,target,*offset,length,*offset,
                             length, error,increment);

             if ( (source!=target) && ( increment > 1 ) )
               {
                 for (i=0,j=*offset; i<increment-1 ;i++,j++ )
                     target[j+1]=source[j+1];
               }

             if(rc==INC_ONE_MORE_TIME)
               {
                 *offset-=increment;
                 if ( (source!=target) && ( increment > 1 ) )
                    for (i=0,j=*offset; i<increment-1 ;i++,j++ )
                      target[j+1]=source[j+1];
               }

           break;

           }                 /* end switch of left orientation               */
     }                       /* end if of left orientation                   */
}

