#define  INCL_DOSERRORS

#include "os2.h"
#include "bdcalls.h"
#include "bdatt.h"
#include "csd.h"
/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    NLSEDITSHAPE                                         */
/*                                                                           */
/*  DESCRIPTIVE NAME:   Character shape determination.                       */
/*                                                                           */
/*  COPYRIGHT:  (c) IBM Corp. 1989.                                          */
/*                                                                           */
/*  FUNCTION : This is the main module that calls the shaping routine and    */
/*             other functions.                                              */
/*             It determines according to the effect, attribute, and         */
/*             orientation, whether to call the input function (when input   */
/*             shaping is required), or to call the edit function (when an   */
/*             editing operation is required), and accordingly, it sets      */
/*             the necessary environment needed for calling these functions. */
/*             Whenever there is reading/writing near the source/target      */
/*             boundaries, a handling routine is called to avoid reading     */
/*             or writing outside the source/target buffer.                  */
/*                                                                           */
/*  ENTRY POINT:  NlsEditShape                                               */
/*   LINKAGE:  CALL FAR (dynamic link API)                                   */
/*                                                                           */
/*    INPUT:   (BidiAtts, Effect, PCSDRec @Source, PCSDRec @Target,          */
/*                                               , @CSDState,increment)      */
/*      BidiAtts  DWORD    - BidiAttributes                                  */
/*      Effect    DWORD    - To select whether input or edit function        */
/*      Source    @OTHER   - Pointer to structure named CSDRec               */
/*      Target    @OTHER   - Pointer to structure named CSDRec               */
/*      CsdState  @OTHER   - Represents the character status                 */
/*      increment DWORD    - The increment step                              */
/*                                                                           */
/*  EXIT-NORMAL: RC=0                                                        */
/*                                                                           */
/*  EXIT-ERROR:                                                              */
/*   ERROR_BIDI_INVALID_ORIENTATION  - Invalid orientation value.            */
/*   ERROR_BIDI_INVALID_COMBINATION  - The length is not a multiple of the   */
/*                                     the increment.                        */
/*   ERROR_BIDI_INVALID_EFFECT       - Invalid effect value.                 */
/*   ERROR_BIDI_INVALID_CSDREC       - Invalid parameter in the i/o structure*/
/*   ERROR_BIDI_INVALID_CSD          - Invalid csd value.                    */
/*   ERROR_BIDI_INVALID_INCREMENT    - Invalid increment value               */
/*   ERROR_BIDI_INVALID_CSDSTATE     - Invalid csdstate  value               */
/*   NO_ERROR_BIDI_RW_INCOMPLETE     - The function does not exit when this  */
/*                                     code occurs but it continues and      */
/*                                     returns it to indicate incomplete     */
/*                                     data reading or writing which may     */
/*                                     affect the output shaped character(s) */
/*                                                                           */
/*  SIDE EFFECT : The value of the Csdstate  should equal to zero the first  */
/*                time the API is called, and should be left untouched by    */
/*                the caller in subsequent calls, because it represents the  */
/*                state of the character and any change in it does not       */
/*                guarantee that the output will be correctly shaped.        */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:                                                 */
/*        CHAR   passary[],  - Array of 3 characters initialized with blanks */
/*               editary[],  - Array of 6 characters initialized with blanks */
/*               firstsucc,  - The first succeeding character after shaping. */
/*               @source,    - Pointer to the source buffer.                 */
/*               @target     - Pointer to the target buffer.                 */
/*                                                                           */
/*        WORD   error=0,    - Returned error initialized with zero.         */
/*               success,    - Flag to indicate the state of reading.        */
/*                             (appears only when reading near boundaries)   */
/*               csd,        - To put the csd byte in it                     */
/*               arraycount, - To hold the returned value from RWTest().     */
/*               aheadcount, - To hold the returned value from RWTest().     */
/*               oldarray,   - To store the old value of arraycount.         */
/*               oldahead,   - To store the old value of arraycount.         */
/*               blank       - Initialized with blank                        */
/*                                                                           */
/*        DWORD  len,j,      - Dummy counters to loop on arrays.             */
/*               orient,     - To store the orientation byte of the BidiAtts */
/*               s_len,      - To hold the length of the source buffer       */
/*               t_len,      - To hold the length of the target buffer       */
/*               s_offset,   - To hold the character offset in the source    */
/*               t_offset    - To hold the character offset in the target    */
/*    GLOBAL DATA DEFINITION:                                                */
/*      Structure CSDRec consisting of:                                      */
/*             DWORD Slength - Length of the structure istself               */
/*             DWORD offset  - Offset of the current character in a buffer   */
/*             DWORD length  - Length of the buffer                          */
/*             @OTHER array  - Pointer to the buffer                         */
/*                                                                           */
/*      ROUTINES: RWTest()      - Read write test near the boundaries        */
/*                editasd()     - Called when an edit operation is needed    */
/*                shape_input() - Called when an input operation is needed   */
/*                pre_deshape() - Called when deshaping is needed            */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/

extern USHORT far pascal _loadds NlsEditShape (ULONG BidiAtts,
                                               LONG Effect,
                                               PCSDRec Source,
                                               PCSDRec Target,
                                               PULONG CSDSTATE,
                                               ULONG Increment)
{

 char           passary[3],                /* Intermediate array for input  */

                editary[6],                /* Intermediate array for edit   */

                firstsucc,                 /* To return the first succeeding*/
                                           /* Character after shaping.      */
                                           /* (not used)                    */

                blank=BLANK_CH;

 int            success=0,                 /* Success is a flag to indicate */
                                           /* complete data reading is done */
                                           /* i.e success=1.                */

                csd,                       /* To put the csd byte in it     */

                arraycount=0, aheadcount=0,

                oldarray=0, oldahead=0,

                i;                         /* Used to loop on passary       */

 unsigned long  s_len,                     /* To hold the source length     */

                t_len,                     /* To hold the target length     */

                s_offset,                  /* To hold the source offset     */

                t_offset ,                 /* To hold the target offset     */

                orient,                    /* To put the orientation byte   */
                                           /* of the bidiAtts in it         */


                len,j ;                    /* Counters to loop on arrays.   */

USHORT          error=0;                   /* Returned error.               */
BYTE            state=0;                   /* contains the value of csdstate*/

 char   far *source, *target;
 PBYTE  CSDCHAR = CSDSTATE;

  s_len    = Source->BufferLength;         /* Here we initialize            */
  t_len    = Target->BufferLength;         /* variables with the            */
  source   = Source->Buffer;               /* values of the structure       */
  target   = Target->Buffer;               /* elements for easy             */
  s_offset = Source->BufferIndex;          /* reference.                    */
  t_offset = Target->BufferIndex;          /*                               */

  csd=(int)BidiAtts & 0x00ff;           /* Bit ANDing to get the CSD value  */
  orient=(BidiAtts>>16) & 0x00ff;       /* Bit ANDing to get the orientation*/

/** this part is added to handle the addition of the field "CSDRec_lenght"*/

  if ((Source->RecLength != 16) || (Target->RecLength != 16))
     return (ERROR_BIDI_INVALID_CSDREC);

/******************* dated 4-11-90 ********************************************/

/* If Increment is zero                                                     */

 if(Increment==0)
   {
     error=ERROR_BIDI_INVALID_INCREMENT;
     return(error);
   }

/* If orientation is not equal to zero or one                                */

 if (orient>1)
   {
     error = ERROR_BIDI_INVALID_ORIENTATION;
     return(error);
   }

/* If the length of source or target is equal to zero                        */

 if( (s_len==0) || (t_len==0) )
   {
     error= ERROR_BIDI_INVALID_CSDREC;
     return (error);
   }

/* If the length of source and target is not a multiple of the Increment     */
/* or if the Increment is greater than the length of the source or target    */

 if( (s_len%Increment!=0) || (t_len%Increment!=0) || (Increment>s_len) ||
        (Increment>t_len) )
   {
     error= ERROR_BIDI_INVALID_COMBINATION;
     return (error);
   }

/* If the offset lies outside the source or target buffer                    */

  if((s_offset>(s_len-Increment)) || (t_offset>(t_len-Increment)) )
   {
     error = ERROR_BIDI_INVALID_CSDREC;
     return (error);
   }


 state =*CSDCHAR;

 switch((int)Effect)            /* Branch according to the "Effect" value    */
  {                             /* either to process input shaping if        */
                                /* Effect=0,or edit shaping if Effect=1      */

   case 0 :                     /* Case of input shaping                     */

     switch (state)             /* Checking the value of the state           */
      {
        case BGN_STATE     :    /*--+                                        */
        case FNL_STATE     :    /*  |                                        */
        case MID_STATE     :    /*  |                                        */
        case SSSD_STATE    :    /*  |--- Case of valid values                */
        case NO_STATE      :    /*  |    for the state                       */
        case LAM_MID_STATE :    /*  |                                        */
        case LAM_FNL_STATE :    /*--+                                        */
        break;

        default :               /* Case of an invalid value of the state     */
          error=ERROR_BIDI_INVALID_CSDSTATE;
          return(error);
        break;

      }
     for (i=0;i<3;i++ ) passary[i]=0x20  ;
                                /* Initializing the passary with blanks      */

     if(orient==1)              /* Case of orientation is right to left      */
       {                        /* i.e memory is scanned from low to high    */
         switch(csd)
          {
            case 0x00:          /* Case of csd on.                           */

             if(s_offset==0)
                                /* Case of lowest element in the buffer      */
                                /* i.e there is no preceding characters      */
              {
                if( state ==0)
                  state  = BGN_STATE;
                           /* First element in the buffer will always have   */
                           /* the state as beginning state                      */
                 passary[0]=source[s_offset];
                                /* Copy current character from source into   */
                                /* passary[0]                                */
                 error=NO_ERROR_BIDI_RW_INCOMPLETE ;

                 shape_input(&state ,&passary[0],
                                     &passary[1], &passary[2],&firstsucc);


                 target[t_offset]=passary[0];
                                /* Copy back the character after shaping     */
              }

             if(s_offset==Increment)
                                /* Case where there is only one preceding    */
                                /* character to the current character        */
              {
                passary[0]=source[s_offset];
                passary[1]=source[s_offset-Increment];

                error=NO_ERROR_BIDI_RW_INCOMPLETE ;

                if(state ==0)
                   pre_edit (& passary[1], & blank,
                            (ULONG) BLANK_CH, &state );
                                /* If state     == 0 then we do not have the */
                                /* current character state .                 */
                                /* so we issue this call to get the current  */
                                /* character state based on its preceding    */
                                /* character assuming that further preceding */
                                /* characters are blanks                     */

                shape_input(&state ,&passary[0],
                            &passary[1], &passary[2],&firstsucc);

                if(t_offset==0)
                   {
                                /* i.e we have a place to write the current  */
                                /* only in the target                        */
                    target[t_offset]=passary[0];
                    error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                                /* This warning error is issued because we   */
                                /* previously read two characters while now  */
                                /* due to boundary condition we wrote only   */
                                /* one character                             */
                   }
                 else
                                /* Here we have a place to write both        */
                                /* the current and the preceding character   */
                   {
                     target[t_offset]=passary[0];
                     target[t_offset-Increment]=passary[1];
                   }
              }

             if (s_offset>=2*Increment)

                                /* Here we can read the current, the first   */
                                /* preceding and the second preceding        */

              {
                for (len=0;len<3;len++)
                  passary[len]=source[s_offset-(len*Increment)];

                if(state ==0)
                  {
                    if(s_offset==2*Increment)
                      {
                       pre_edit (&passary[1], &passary[2],
                             (ULONG)BLANK_CH, (PUCHAR)&state );
                                /* We issue this call to get the state of the*/
                                /* current character based on its two        */
                                /* preceding characters assuming the third   */
                                /* preceding character is a blank because it */
                                /* does not exists in the source buffer      */
                       error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                       }
                    else
                       pre_edit (&passary[1], &passary[2],
                             (ULONG)source[s_offset-(3*Increment)],
                                            (PUCHAR)&state );
                                /* Here we can read the third preceding      */
                                /* character and we don't have to assume it  */
                                /* a blank character                         */

                  }

                shape_input(&state ,&passary[0],
                            &passary[1], &passary[2],&firstsucc);

                if(t_offset<(2*Increment))
                                /* This is the case where we don't have      */
                                /* enough space to write the current and its */
                                /* two preceding character into target buffer*/

                  {

                    for(len=0,j=0;len<=t_offset;len+=Increment,j++)
                      target[t_offset-len]=passary[j];
                      error = NO_ERROR_BIDI_RW_INCOMPLETE ;
                   }
                 else
                                /* We have enough space to write all         */
                                /* characters previously read                */

                   {
                      for (len=0;len<3;len++)
                         target[t_offset-(len*Increment)]=passary[len];
                    }
              }
            break;
            case 0x01 :         /* case of CSD = passthru */

             if(source!=target)
                                /* If source and target are not totally      */
                                /* overlapped, perform copying               */

               target[t_offset]=source[s_offset];

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

                pre_deshape (BidiAtts,source,target,s_offset,s_len,
                t_offset, t_len,&error,Increment);
             break;

             default:
                                /* This is the case where there is no match  */
                                /* in the CSD value passed in the Bidi       */
                                /* Attributes                                */

                error=ERROR_BIDI_INVALID_CSD;
             break;
          }                     /* End switch of right orientation           */
       }                        /* End if of right orientation               */

     if (orient==0)             /* Case of orientation is left to right      */
       {
         switch (csd)
          {
            case 0x00:          /* Case of CSD indicates shaping             */

             if(s_offset==s_len-Increment )
                                /* Case of current with no preceding         */
                                /* characters                                */
               {

                 if(state ==0)
                   state = BGN_STATE;
                                /* have the state as beginning state          */
                  passary[0]=source[s_offset];
                  error=NO_ERROR_BIDI_RW_INCOMPLETE ;

                  shape_input(&state ,&passary[0],
                              &passary[1], &passary[2],&firstsucc);
                  target[t_offset]=passary[0];
               }

             if( s_offset == (s_len-2*Increment) )
                                /* case of one preceding character to the    */
                                /* current character                         */
               {
                 passary[0]=source[s_offset];
                 passary[1]=source[s_offset+Increment];

                 error=NO_ERROR_BIDI_RW_INCOMPLETE ;

                 if(state ==0)
                    pre_edit (& passary[1], & blank, (ULONG)BLANK_CH,
                              &state );
                 shape_input(&state ,&passary[0],
                             &passary[1], &passary[2],&firstsucc);

                 if(t_offset==t_len-Increment)
                                /* Case of no enough space to write the      */
                                /* preceding */
                   {
                     target[t_offset]=passary[0];
                     error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                   }
                 else
                                /* We can write all characters previously    */
                                /* read                                      */
                   {
                     target[t_offset]=passary[0];
                     target[t_offset+Increment]=passary[1];
                   }
               }

             if (s_offset+2*Increment<=s_len-Increment)
                                /* Case where we can read from source the    */
                                /* current character and its two preceding   */
                                /* characters                                */
               {
                 for (len=0;len<3;len++)
                    passary[len]=source[s_offset+(len*Increment)];

                 if(state ==0)
                                /* call pre_edit to get the state of the     */
                                /* current character                         */
                    {
                       if (s_offset+2*Increment==s_len-Increment)
                        {
                                /* if we don't have a third preceding        */
                                /* character assume it blank in the call     */
                          pre_edit (&passary[1], &passary[2],
                                   (ULONG)BLANK_CH, (PUCHAR)&state );
                          error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                         }
                       else
                           pre_edit (&passary[1], &passary[2],
                                    (ULONG)source [s_offset+(3*Increment)],
                                     (PUCHAR)&state );
                    }
                 shape_input(&state ,&passary[0],
                             &passary[1], &passary[2],&firstsucc);

                 if(t_offset+(2*Increment)>t_len-Increment)
                                /* if we can't write the current and its two */
                                /* preceding characters                      */
                   {
                     for(len=0;t_offset<=t_len-Increment;len++)
                       {
                         target[t_offset]=passary[len];
                         t_offset+=Increment;
                       }
                     error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                                /* warning error indicates incomplete data   */
                                /* writing                                   */
                   }
                 else
                   {
                     for (len=0;len<3;len++)
                       target[t_offset+(len*Increment)]=passary[len];
                                /* write all the characters into target      */
                   }
               }
            break;
            case 0x01 :         /* case of passthru                          */

              if(source!=target)
                 target[t_offset]=source[s_offset];
                                /* copy the current character from source    */
                                /* into target                               */
            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                   */
              pre_deshape (BidiAtts,source,target,s_offset,s_len,t_offset,t_len,
                           &error,Increment);
            break;
            default :
               error=ERROR_BIDI_INVALID_CSD;
                                /* error mismatch csd value                  */
            break;
          }                     /* end switch of left orientation            */
       }                        /* end if of left orientation                */
    break;
    case 1:                     /* Case of edit shape                        */
      if(orient==1)             /* If orientation is right to left i.e :     */
        {                       /* memory is scanned from low to high        */
          switch(csd)           /* Branching according to the csd value      */
              {
               case 0x00:       /* Case of shaping is required               */

                if( (s_offset>=3*Increment) && (s_offset<=s_len-3*Increment) )
                                /* case where we can read all characters, the*/
                                /* current + 5 surroundings                  */

                  {
                   for(len=0;len<6;len++)
                    editary[len]=source[(s_offset-3*Increment)+(len*Increment)];
                    success=1;  /* this is to indicates successful reading   */
                   }
                 else           /* case of boundary manipulation             */
                   {
                     for(len=0;len<6;len++)
                       editary[len]=0x20;
                                /* Initialize the editarray with blanks so   */
                                /* that characters not read are replaced by  */
                                /* blanks                                    */

                     RWTest(&s_offset, Increment,s_len, orient,
                           &arraycount, &aheadcount);
                                /* Call RWTest to determine where to start   */
                                /* writing in the editarray (arraycount),    */
                                /* and to determine how may characters to    */
                                /* read ahead from source (aheadcount).      */
                                /* It also modifies the s_offset position to */
                                /* match with the value of arraycount        */

                     oldarray=arraycount;
                     oldahead=aheadcount;
                                /* Save those values in oldarray and oldahead*/
                                /* so that in case of incomplete data writing*/
                                /* we know what characters are previously    */
                                /* read                                      */

                     for(len=0,j=arraycount; len<(ULONG)aheadcount; len++,j++ )
                              editary[j] = source[s_offset+(len*Increment)];
                                /* reading characters according to arraycount*/
                                /* and aheadcount                            */

                     error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                                /* this is a warning error indicating        */
                                /* incomplete data reading happens           */
                    }

                 editasd(editary,(unsigned long)'r');

                 if( (t_offset>=3*Increment) && (t_offset<=t_len-3*Increment) )
                                /* If we can write the current and all its   */
                                /* surrounding characters                    */
                  {
                   if(success==1)
                                /* If safe reading was previously done       */

                     for(len=0;len<6;len++)
                       target[(t_offset-3*Increment)+(len*Increment)]
                                      = editary[len];
                                /* write all the characters in target        */

                    else        /* case of incomplete data reading was done  */

                     for(len=0,j=oldarray; len<(ULONG)oldahead; len++,j++ )
                      target[t_offset-(3-arraycount)*Increment+(len*Increment)]
                             =editary[j];
                                /* write only data previously read           */

                    }
                   else         /* case where we write the current but not   */
                                /* all its surrounding characters            */
                   {
                    error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                                /* warning of incomplete data writing        */

                     if(success==1)
                                /* case of successful reading was done       */
                       {
                        RWTest( &t_offset, Increment,t_len, orient,
                                &arraycount, &aheadcount);
                                /* get arraycount and aheadcount for the     */
                                /* target                                    */

                        for(len=0,j=arraycount; len<(ULONG)aheadcount; len++,j++ )
                        target[t_offset+(len*Increment)] = editary[j];
                                /* write characters to source according to   */
                                /* arraycount and aheadcout values           */

                       }
                      else      /* case of incomplete data reading was done  */
                       {

                        RWTest( &t_offset, Increment,t_len, orient,
                           &arraycount, &aheadcount);
                                /* get information about available place to  */
                                /* write in target                           */

                        if(arraycount <= oldarray)
                                /* we do this comparison so that we write    */
                                /* the characters allowed due to boundary    */
                                /* conditions of target and which were read  */
                                /* due to boundary condition in source       */
                         {
                            t_offset=t_offset+(oldarray-arraycount)*Increment;
                                /* adjust the target offset value            */
                            aheadcount -= oldarray-arraycount;
                                /* find the new value of aheadcount          */
                            arraycount=oldarray;
                                /* make the new value of arraycount = the    */
                                /* old value oldarray                        */
                          }
                        else

                            oldahead -= arraycount-oldarray;

                        if(oldahead<aheadcount)
                           aheadcount=oldahead;

                         for(len=0,j=arraycount; len<(ULONG)aheadcount; len++,j++ )
                         target[t_offset+(len*Increment)] = editary[j];
                                /* writing available characters              */
                        }
                       }
                break;
                case 0x01 :     /* case of passthru                          */

                         if(source!=target)
                         target[t_offset]=source[s_offset];
                                /* copy the character from source to target  */
                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                   */
                  pre_deshape (BidiAtts,source,target,s_offset,s_len,t_offset,
                        t_len, &error,Increment);
                break;

                default:error=ERROR_BIDI_INVALID_CSD;
                break;
              }                 /* end switch of right orientation           */
           }                    /* end if of right orientation               */

       if (orient==0)           /* case of orientation is left to right      */
         {                      /* memory is scanned from high to low.        */
          switch (csd)
             {
              case 0x00:        /* case of csd on.                           */

                 if( (s_offset>=2*Increment) && (s_offset<=s_len-4*Increment) )
                  {
                                /* case where we can read all the characters */
                                /* current + 5 surroundings                  */
                   for(len=0;len<6;++len)
                    editary[len]=source[(s_offset-2*Increment)+(len*Increment)];

                   success=1;   /* this flag indicates complete data reading */
                  }
                 else           /* case of incomplete data reading           */
                   {
                     for(len=0;len<6;len++)
                       editary[len]=0x20;
                                /* Initialize the editarray with blanks so   */
                                /* that characters not read are replaced by  */
                                /* blanks                                    */

                     RWTest( &s_offset, Increment,s_len, orient,
                           &arraycount, &aheadcount);
                                /* Call RWTest to determine where to start   */
                                /* writing in the editarray (arraycount),    */
                                /* and to determine how may characters to    */
                                /* read ahead from source (aheadcount).      */
                                /* It also modifies the s_offset position to */
                                /* match with the value of arraycount        */

                     oldarray=arraycount;
                     oldahead=aheadcount;

                                /* Save those values in oldarray and oldahead*/
                                /* so that in case of incomplete data writing*/
                                /* we know what characters are previously    */
                                /* read                                      */
                     for(len=0,j=arraycount; len<(ULONG)aheadcount; len++,j++ )
                              editary[j] = source[s_offset+(len*Increment)];
                                /* reading characters according to arraycount*/
                                /* and aheadcount                            */

                     error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                                /* this is a warning error indicating        */
                                /* incomplete data reading happens           */
                    }

                 editasd(editary,(unsigned long)'l');

                 if( (t_offset>=2*Increment) && (t_offset<=t_len-4*Increment) )
                                /* If we can write the current and all its   */
                                /* surrounding characters                    */
                  {

                   if(success==1)
                                /* If safe reading was previously done       */
                     for(len=0;len<6;len++)
                      target[(t_offset-2*Increment)+(len*Increment)]
                              =editary[len];
                                /* write all the characters in target        */

                    else        /* case of incomplete data reading was done  */

                     for(len=0,j=oldarray; len<(ULONG)oldahead; len++,j++ )
                      target[t_offset-(2-arraycount)*Increment+(len*Increment)]
                              =editary[j];
                                /* write only data previously read           */
                    }
                   else         /* case where we write the current but we    */
                                /* can not write all its surrounding         */
                                /* characters                                */
                    {

                     error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                                /* warning of incomplete data writing        */
                     if(success==1)
                      {

                        RWTest( &t_offset, Increment,t_len, orient,
                           &arraycount, &aheadcount);
                                /* get arraycount and aheadcount for the     */
                                /* target                                    */

                        for(len=0,j=arraycount; len<(ULONG)aheadcount; len++,j++ )
                        target[t_offset+(len*Increment)] = editary[j];
                                /* write characters to source according to   */
                                /* arraycount and aheadcout values           */

                      }

                     else       /* case of incomplete data reading was done  */

                      {
                        RWTest( &t_offset, Increment,t_len, orient,
                           &arraycount, &aheadcount);
                                /* get information about available place to  */
                                /* write in target                           */

                         if(arraycount <= oldarray)
                                /* we do this comparison so that we write    */
                                /* the characters allowed due to boundary    */
                                /* conditions of target and which were read  */
                                /* due to boundary condition in source       */
                           {
                            t_offset=t_offset+(oldarray-arraycount)*Increment;

                            aheadcount -= oldarray-arraycount ;

                            arraycount=oldarray;
                           }
                         else
                            oldahead -= arraycount-oldarray;

                         if(oldahead<aheadcount)
                            aheadcount=oldahead;

                         for(len=0,j=arraycount; len<(ULONG)aheadcount; len++,j++ )
                          target[t_offset+(len*Increment)] = editary[j];
                       }
                      }
                break;
                case 0x01 :     /* case of passthru                          */
                         if(source!=target)
                         target[t_offset]=source[s_offset];
                         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                   */
                  pre_deshape (BidiAtts,source,target,s_offset,s_len,t_offset,
                               t_len, &error,Increment);
                break;
                default:
                  error=ERROR_BIDI_INVALID_CSD;
                break;
              }                 /* end switch of left orientation            */
           }                    /* end if of left orientation                */
    break;

    default :
     error = ERROR_BIDI_INVALID_EFFECT ;
    break;
  }                             /* end switch                                */

   *CSDCHAR = state;
   return(error);
 }                              /* end function                              */

/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    PRE_DESHAPE                                          */
/*                                                                           */
/*  DESCRIPTIVE NAME:   To set the needed environment for calling the deshape*/
/*                      function.                                            */
/*                                                                           */
/*  FUNCTION : This function is called in case of deshaping is needed,       */
/*             it interfaces between the nlseditshape module and the deshape */
/*             module. It copies characters from source according to the     */
/*             orientation and the Increment, calls the deshape function,    */
/*             and writes back the result into target.                       */
/*                                                                           */
/*  ENTRY POINT:  pre_deshape                                                */
/*      LINKAGE:  CALL NEAR (from NlsEditShape and block_interface)          */
/*                                                                           */
/*      INPUT:    (BidiAtts,@source,@target s_offset,s_len,t_offset,t_len,   */
/*                 @error,Increment)                                         */
/*                 BidiAtts  DWORD     - Bidi Attributes                     */
/*                 source    @OTHER    - Pointer to the source buffer        */
/*                 target    @OTHER    - Pointer to the target buffer        */
/*                 s_offset  @DWORD    - Current character position in source*/
/*                 s_len     @DWORD    - Length of the source buffer         */
/*                 t_offset  @DWORD    - Current character position in target*/
/*                 t_len     @DWORD    - Length of the target buffer         */
/*                 error     @DWORD    - Pointer to the returned error       */
/*                 Increment DWORD     - Increment step                      */
/*                                                                           */
/*  EXIT-NORMAL: RC = 0                                                      */
/*                                                                           */
/*  EXIT-ERROR:  RC = INC_ONE_MORE_TIME                                      */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:                                                 */
/*                                                                           */
/*         WORD    orient,    - To contain the value of the orientation byte */
/*                              in the BidiAtts                              */
/*         WORD    success    - Flag to indicate complete data reading       */
/*         WORD    csd        - To contain the value of the csd byte in the  */
/*                              BidiAtts                                     */
/*         CHAR    passary[]  - Intermediate array                           */
/*                 special[]  - Array containing the LAMALEF shapes          */
/*                 yeh[]      - Array containing the YEH_HAMZA_CH            */
/*                                                                           */
/*    ROUTINES:    deshape()  - The deshape routine                          */
/*                 verify()   - Called to verify the existence of a          */
/*                              character in an array.                       */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/
unsigned long pre_deshape ( unsigned long BidiAtts,char far *source,
              char far *target, unsigned long s_offset, unsigned long s_len,
              unsigned long t_offset, unsigned long t_len, PUSHORT error,
              unsigned long increment)
{
 int orient,
     csd,
     success=0;

 char passary[2];

 static char special[]={0x99, 0x9A, 0x9D, 0x9E, 0xF9, 0xFA,'\0'};
 static char yeh[]={0xC6,'\0'};
                                /* these are special characters where we     */
                                /* need to read the succeeding character     */
                                /* which will change after deshaping         */

 orient=(int)(BidiAtts>>16) & 0x00ff;
 csd =(int)(BidiAtts & 0x000000ff);
                                /* calculate the orientation and the csd     */
                                /* value of the Bidi Attributes              */
 if(orient==1)                  /* case of right to left orientation         */
   {
        passary [0]= source [s_offset];
                                /* read the current character into passary[0]*/

        if(((verify((unsigned long)passary[0],special)==0)&&(csd==0x10))
                                ||
        ((verify((unsigned long)passary[0],yeh)==0)&&((csd==0x13)||(csd==0x14))))
                                /* check if we are in the case where we have */
                                /* to read the succeeding character.         */
                                /* It is the case of:                        */
                                /* current is LAMALEF and csd = base shape   */
                                /*               or                          */
                                /* current is YEH_HAMZA_CH and csd= final or */
                                /* or isolated shapes                        */

         {
           if(s_offset+increment>(s_len-increment))
                                /* if we can't read the succeeding character */
            *error=NO_ERROR_BIDI_RW_INCOMPLETE ;
                                /* warning error to indicate incomplete      */
                                /* data reading                              */
           else                 /* we can read the succeeding character      */
            {
             passary [1]= source [s_offset+increment];
             success=1;         /* this flag to indicate successful reading  */
            }

           if( ((passary[0]==yeh[0]) && (success==0)) )

             deshape (passary,passary,1l,BidiAtts);
           else
             deshape (passary,passary,2l,BidiAtts);

           target [t_offset]=passary [0];
                                /* write the current character into the      */
                                /* target at the offset position             */

           if (t_offset+increment>(t_len-increment))
                                /* case where we can't write the succeeding  */
                                /* character                                 */
            *error=NO_ERROR_BIDI_RW_INCOMPLETE ;
           else
            {

             if(success==1);
                                /* if complete data reading was done         */
              {

                 target[t_offset+increment]=passary[1];
                                /* write the current character into target   */

                 if(passary[1]!=yeh[0])
                 return(INC_ONE_MORE_TIME);
                                /* return a flag indicating that the         */
                                /* succeeding character already shaped and   */
                                /* we don't need to read it again.           */
                 else
                                /* case of successive YEH_HAMZA, do not      */
                                /* return INC_ONE_MORE_TIME until we get the */
                                /* next YEH_HAMZA                            */
                 return(0);

               }
            }
         }
        else                    /* case where the current is not a special   */
                                /* character                                 */
         {
           deshape (passary,passary,1l,BidiAtts);
                                /* deshape the current character             */
           target [t_offset]=passary [0];
                                /* write the current character into the      */
                                /* target at target offset position          */
           return(0);
                                /* return zero i.e no need to jump ahead one */
                                /* character                                 */
         }
    }
  if(orient==0)                 /* orientation is left                       */
    {
        passary [1]= source [s_offset];
                                /* read the current character in passary[1]  */
        if(((verify((unsigned long)passary[1],special)==0)&&(csd==0x10))
                                ||
        ((verify((unsigned long)passary[1],yeh)==0)&&((csd==0x13)||(csd==0x14))))

                                /* if the current is a special character     */
         {
           if((long)(s_offset-increment)<0)
                                /* if we can't read the succeeding character */
            *error=NO_ERROR_BIDI_RW_INCOMPLETE ;
           else
            {
             passary [0]= source [s_offset-increment];
             success=1;         /* this flag indicates complete data reading */
            }

           if( (passary[1]==yeh[0]) && (success==0) )

            deshape (&passary[1],&passary[1],1l,BidiAtts);
           else
            deshape (passary,passary,2l,BidiAtts);

           target [t_offset]=passary [1];

           if ((long)(t_offset-increment)<0)
            *error=NO_ERROR_BIDI_RW_INCOMPLETE ;
           else
            {
              if(success==1)
                {
                  target[t_offset-increment]=passary[0];

                  if(passary[0]!=yeh[0])
                    return(INC_ONE_MORE_TIME);
                  else
                    return(0);
                }
            }
         }
        else
         {
           deshape (&passary[1],&passary[1],1l,BidiAtts);
           target [t_offset]=passary [1];
           return(0);
         }
     }
 }
/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    RWTEST                                               */
/*                                                                           */
/*  DESCRIPTIVE NAME:   To get information when reading/writing near         */
/*                      Boundaries                                           */
/*                                                                           */
/*  FUNCTION : This function is called in case of edit function is required  */
/*             and there is reading/writing near the boundaries.             */
/*             This is to prevent reading/writing outside the source/target  */
/*             buffer.                                                       */
/*             It returns the position in editary (arraycount) where we can  */
/*             start reading in/writing from characters, it also returns     */
/*             the number of available characters that can be read/written   */
/*             (aheadcount). Also it adjusts the position of offset in the   */
/*             buffer (source or target) to start read/write operation.      */
/*                                                                           */
/*  ENTRY POINT:  RWTest                                                     */
/*      LINKAGE:  CALL NEAR (from NlsEditShape)                              */
/*                                                                           */
/*      INPUT:    (@Offset,Increment,length,orient,@arraycount,@aheadcount)  */
/*         Offset      @DWORD   - Current character position in source/target*/
/*         Increment   DWORD    - Increment step                             */
/*         length      DWORD    - Length of the source/target                */
/*         orient      DWORD    - Orientation                                */
/*         arraycount  @WORD    - Start position in editary                  */
/*         aheadcount  @WORD    - How many characters to be read or written  */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURNED VALUE                                           */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/
void RWTest (unsigned long *Offset, unsigned long Increment,
unsigned long length, unsigned long orient, int *arraycount, int *aheadcount)
{

  if(orient==0)                 /* orientation is left to right              */
   {
    if( (*Offset ==0 ) || (*Offset == Increment) )
     {
      *arraycount =(int)(2-(*Offset/Increment));
                                /* This parameter indicates where to start   */
                                /* writing or reading from the edit array    */
      *aheadcount = LEN_EDIT_ARRAY-*arraycount;
                                /* This parameter indicates how many chars   */
                                /* we can read (or write) from the source    */
                                /* (or target) in editary, starting from the */
                                /* position "arraycount" in editary.         */
      *Offset = 0;
                                /* Here we modify the position where we      */
                                /* read from source (or write into target)   */
                                /* to match the position in edit array set by*/
                                /* the arraycount parameter                  */
     }
    else
     {
      *arraycount = 0;
      *aheadcount =LEN_EDIT_ARRAY;
                                /* here we assume that we can read ahead all */
                                /* the characters                            */
      *Offset =*Offset - 2*Increment;
                                /* adjusting the offset to point to where we */
                                /* start to read                             */
     }
   }
  if(orient==1)                 /* case of orientation is right to left      */
   {
    if( (*Offset == 0) || (*Offset == Increment) || (*Offset == 2*Increment) )
                                /* if the offset is near the beginning of the*/
                                /* buffer                                    */
     {
      *arraycount =(int) (3-(*Offset/Increment));
      *aheadcount = LEN_EDIT_ARRAY-(*arraycount);
      *Offset=0;
     }
    else
     {
      *arraycount = 0;
      *aheadcount =LEN_EDIT_ARRAY;
      *Offset = *Offset - 3*Increment;
     }
   }
  if( ((length-*Offset) / Increment) <(ULONG) (*aheadcount) )
                                /* if the buffer boundary is too near so that*/
                                /* we can not write ahead according to the   */
                                /* assumed value of aheadcount               */
   *aheadcount =(int)((length-*Offset)/Increment);
                                /* set a new value of aheadcount             */
 }

/*----------------Initialization of the mother arabic array-----------------*/

static char arbary[]={0xf1,0xf0,0xe0,0xc2,0xa2,0xc3,0xa5,
                      0xc4,0xa6,0xa7,0xc6,0xc7,0xa8,0xa9,
                      0xc8,0xc9,0xaa,0xca,0xab,0xcb,0xad,
                      0xcc,0xae,0xcd,0xaf,0xce,0xcf,0xd0,
                      0xd1,0xd2,0xbc,0xd3,0xbd,0xd4,0xbe,
                      0xd5,0xeb,0xd6,0xd7,0xd8,0xdf,0xc5,
                      0xd9,0xec,0xee,0xed,0xda,0xf7,0xba,
                      0xe1,0xf8,0xe2,0xfc,0xe3,0xfb,0xf9,
                      0xfa,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,
                      0xe4,0xef,0xe5,0xf2,0xe6,0xf3,0xe7,
                      0xf4,0xe8,0xe9,0xf5,0xfd,0xf6,0xea,'\0'};

/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    EDITASD                                              */
/*                                                                           */
/*  DESCRIPTIVE NAME:   Editing using the input CSD                          */
/*                                                                           */
/*  FUNCTION : The edit function is made to determine the shape of the       */
/*             current character and link it with its surrounding characters */
/*             (five characters).                                            */
/*                                                                           */
/*  ENTRY POINT:  editasd                                                    */
/*      LINKAGE:  CALL NEAR (from NlsEditsShape)                             */
/*                                                                           */
/*      INPUT: (editarray , orient)                                          */
/*             editarray  @CHAR   - Array of fixed length (six characters)   */
/*             orient     DWORD   - 'l' if LTR orientation or 'r' for RTL    */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURNED VALUE                                           */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:                                                 */
/*        CHAR   succeed1         - To hold the succeeding character         */
/*        DWORD  olds3            - initialized with the third succeeding    */
/*        CHAR   edit_virtual     - To keep track with the character state   */
/*        CHAR   oldc             - To hold the current character if it is   */
/*                                  a YEH_HAMZA_CH                           */
/*        CHAR   olds1            - To hold the first succeeding character   */
/*                                  in case of current is a YEH_HAMZA_CH     */
/*        CHAR   delay            - To indicate that the special case of     */
/*                                  YEH_HAMZA_CH                             */
/*        WORD   k                - dummy variable                           */
/*                                                                           */
/*        @OTHER TIAL_CHAR        - Array containing characters who needs    */
/*                                  the TAIL to have their final shape.      */
/*                                                                           */
/*    GLOBAL DATA DEFINITION:                                                */
/*        CHAR   arbary           - array containing all arabic characters   */
/*                                                                           */
/*    ROUTINES:  shape_input()    - called when an input operation is needed */
/*               verify()         - called to verify the existence of a      */
/*                                  character in an array.                   */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/
void  editasd (char editarray[] ,unsigned long orient)
{
   unsigned char edit_virtual,

                 succeed1,

                 oldc,

                 olds1;

   unsigned long olds3;

   static char TAIL_CHAR[] = {0xD3,0xD4,0xD5,0xD6,0xBC,0xBD,0xBE,0xEB,'\0'};
   static char LAMALEF_CHAR[] = {0x99,0x9A,0x9D,0x9E,0xF9,0xFA,'\0'};

   int k,

       delay=0;

if (orient=='r')                /* case of orientation is right to left      */
{
   olds3=editarray[5];          /* saving the second succeeding character    */

   if((char)editarray[3]==(char)YEH_HAMZA_CH)
     {
       if (verify((unsigned long)editarray[4],arbary)==1)
                                /* a special case of YEH_HAMZA_CH followed   */
                                /* by a non arabic character so we save the  */
                                /* YEH_HAMZA_CH and the non arabic character */
                                /* and write them back after shaping         */
                                /* the "editarray"                           */
         {
           oldc=editarray[3];   /* saving the current character              */
           olds1=editarray[4];  /* saving the first succeeding character     */
           delay=1;             /* flag to indicate the case of YEH_HAMZA_CH */
         }
     }

   if( ((char)editarray[3]==(char)ISOLATED_SHADDA_CH) ||
       ((char)editarray[3]==(char)CONNECTED_SHADDA_CH) )
                                /* if the current character is a SHADDA_CH   */
    {
      if ((verify((unsigned long)editarray[2],TAIL_CHAR)==0)&&
          ((char)editarray[4]==(char)BLANK_CH))
                                /* if the preceding character is of the seen */
                                /* family and the first succeeding is a BLANK*/
        {
           editarray[4]=0xE0;   /* put TATWEEL in the frist succeeding       */
           delay=2;             /* flag to indicate the case of SHADDA_CH    */
        }
    }

   pre_edit (&editarray[2], &editarray[1], (unsigned long)editarray[0],
             (PUCHAR)&edit_virtual);
                                /* the pre_edit function determines the state*/
                                /* of the current character according to the */
                                /* first and second preceding character      */
   k=3;

   while (k<=5)
    {
      shape_input((PBYTE)&edit_virtual,&editarray[k],&editarray[k-1],
                                         &editarray[k-2],&succeed1);
      k++;
    }

   if( (verify(olds3,arbary)==0) )
                                /* if the second succeeding character        */
                                /* is an arabic character                    */
   editarray[5]=(char)olds3;
                                /* write the character back and override the */
                                /* second succeeding character after shaping */

   if (delay==1)
    {                           /* if case of YEH_HAMZA_CH                   */
      editarray[3]=oldc;        /* override the current and the first        */
      editarray[4]=olds1;       /* succeeding with their old values          */
    }

   if (delay==2)
    {                               /* if case of SHADDA preceeded by a SEEN */
      editarray[4]=(char)BLANK_CH;  /* succeeding with their old values      */
    }



  }

if (orient=='l')                /* if orientation is left to right           */
 {
   olds3=editarray[0];

   if((char)editarray[2]==(char)YEH_HAMZA_CH)
     {
       if (verify((unsigned long)editarray[1],arbary)==1)
                                /* a special case of YEH_HAMZA_CH followed   */
                                /* by a non arabic character so we save the  */
                                /* YEH_HAMZA_CH and the non arabic character */
                                /* and write them back after shaping         */
                                /* the "editarray"                           */
         {
           oldc=editarray[2];   /* saving the current character              */
           olds1=editarray[1];  /* saving the first succeeding character     */
           delay=1;             /* flag to indicate the case of YEH_HAMZA_CH */
         }
     }
   if( ((char)editarray[2]==(char)ISOLATED_SHADDA_CH) ||
       ((char)editarray[2]==(char)CONNECTED_SHADDA_CH) )
                                /* if the current character is a SHADDA_CH   */
    {
      if ( (verify((unsigned long)editarray[3],TAIL_CHAR)==0) &&
           ((char)editarray[1] == (char)BLANK_CH) )

                                /* if the preceding character is of the seen */
                                /* family                                    */
        {
           editarray[1]=0xE0;   /* put TATWEEL in the frist succeeding       */
           delay=2;             /* flag to indicate the case of SHADDA_CH    */

        }
    }

   pre_edit (&editarray[3], &editarray[4], (unsigned long)editarray[5],
             (PUCHAR)&edit_virtual);
                                /* the pre_edit function determines the state*/
                                /* of the current character according to the */
                                /* first and second preceding character      */
   k=2;

   while (k>=0)
    {
      shape_input((PBYTE)&edit_virtual,&editarray[k],&editarray[k+1],
                                         &editarray[k+2],&succeed1);
      k--;
    }

  if( (verify(olds3,arbary)==0 ) )
                                /* if the second succeeding character is     */
                                /* is an arabic character                    */

     if(! ( ((char)editarray[1] == (char)ISOLATED_SHADDA_CH ) &&
         (verify((char)editarray[2],LAMALEF_CHAR)==0l) ))

                                /* we do not want to restor the arabic char  */
                                /* if the current char is a lamalef and the  */
                                /* first succeeding is an ISOLATED_SHADDA,   */
                                /* because the second succeeding sould       */
                                /* remain a blank .....4-6-90                */

        editarray[0]=(char)olds3;
                                /* write the character back and override the */
                                /* second succeeding character after shaping */
   if (delay==1)
    {                           /* if case of YEH_HAMZA_CH                   */
      editarray[2]=oldc;        /* override the current and the first        */
      editarray[1]=olds1;       /* succeeding with their old values          */
    }

   if (delay==2)
    {                              /* if case of SHADA replace the          */
      editarray[1]=(char)BLANK_CH; /* succeeding with their old values      */
    }
  }
}
/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    VERIFY                                               */
/*                                                                           */
/*  DESCRIPTIVE NAME:   verifying the existence of a character in an array   */
/*                                                                           */
/*  FUNCTION : The verify function returns a value of zero if the character  */
/*             passed (as a parameter) exists in the array passed,           */
/*                                                                           */
/*  ENTRY POINT:  verify                                                     */
/*      LINKAGE:  CALL NEAR (from editasd() and pre_deshape())               */
/*                                                                           */
/*      INPUT:  ( checkc , checkary)                                         */
/*              checkary  @CHAR    - Array of characters null terminated     */
/*              checkc    DWORD    - character to be verified                */
/*                                                                           */
/*  EXIT-NORMAL: Returning zero or one                                       */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:                                                 */
/*        WORD   j           - dummy variable to loop on the array           */
/*        WORD   flag       - returned value                                 */
/*                                                                           */
/*    GLOBAL DATA DEFINITION:                                                */
/*        CHAR   arbary       - array containing all arabic characters       */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/
unsigned long verify (unsigned long checkc , char checkary[])

 {
   int j=0 ,

       flag=1;

    while ( checkary[j] != '\0')
     {
     if ((CHAR)checkc != checkary[j])
        j++;
     else
       {
         flag=0;  /* flag=0 i.e: the character does exist in the array */
         return(flag);
       }
     }
    return(flag);
  }

/******************** START OF SPECIFICATIONS ********************************/
/*                                                                           */
/* SUBROUTINE  NAME:  PRE_EDIT                                               */
/*                                                                           */
/* DESCRIPTIVE NAME:  get the state for the current character                */
/*                                                                           */
/* FUNCTION: determines the state of the current character according to      */
/*           its two preceding characters which may also be changed.         */
/*                                                                           */
/* ENTRY POINT:  PRE_EDIT                                                    */
/*    LINKAGE:   NEAR CALL (from the editasd)                                */
/*                                                                           */
/*    INPUT:     (asd_current,asd_first_prec, asd_sec_prec, state)           */
/*           @CHAR   asd_current          - current character                */
/*           @CHAR   asd_first_prec       - first previous character.        */
/*           CHAR    asd_sec_prec         - second previous character        */
/*           @CHAR   state                - state of the current char        */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURN VALUE                                             */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:                                                 */
/*        BYTE   group_num   - group number of the currently                 */
/*                             classified character                          */
/*                                                                           */
/*    GLOBAL DATA DEFINITION: NONE                                           */
/*                                                                           */
/*    ROUTINES:                                                              */
/*           ADJUST1()                                                       */
/*           ADJUST2()                                                       */
/*           CLASSIFY()                                                      */
/*           FIND_CHAR()                                                     */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/*                                                                           */
/********************* END OF SPECIFICATIONS *********************************/
void pre_edit ( PUCHAR asd_current, PUCHAR asd_first_prec, ULONG asd_sec_prec,
                PUCHAR state )
{
   BYTE group_num;

   asd_sec_prec &= 0x000000ff;
                                /* take the lower byte of the long parameter*/
                                /* It contains the second preceding char    */
   classify( (ULONG)*asd_current, &group_num );
                                /* classify will return the group number of */
                                /* the passed character                     */
   switch (group_num) {

   case  2 :
      find_char( (ULONG)*asd_current, 2L, 3L, asd_current );
                                /* find_char will map *asd_current from     */
                                /* group_num to group 3 and will return the */
                                /* mapped character at the location pointed */
                                /* to by asd_current                        */
      *state = SSSD_STATE;
   break;

   case 27 :
      classify( (ULONG)*asd_first_prec, &group_num );
      adjust1( (ULONG)group_num, asd_first_prec, asd_sec_prec, (PBYTE)state );
                                /* adjust1 handles all asd_first_prec char  */
                                /* that are in end of word position. it will*/
                                /* put asd_first_prec in initial or mid word*/
                                /* position and sets the state              */
      if (*state != BGN_STATE)
         find_char( (ULONG)*asd_current, 27L, 28L, asd_current );
                                /* this maps the isolated shadda to the     */
                                /* connected shadda                         */
   break;

   case 28 :
      classify( (ULONG)*asd_first_prec, &group_num );
      *state = NO_STATE;
      adjust2( (ULONG)group_num, asd_sec_prec,(PBYTE) state );

      if (*state == NO_STATE)
        {
          find_char( (ULONG)*asd_current, 28L, 27L, asd_current );
                                /* this maps the connected shadda to the    */
                                /* isolated shadda                          */
          *state = BGN_STATE;
        }
   break;

   default:
      *state = NO_STATE;
      adjust1( (ULONG)group_num, asd_current, (ULONG)*asd_first_prec,
               (PBYTE)state );

      if (*state == NO_STATE)
         adjust2( (ULONG)group_num, (ULONG)*asd_first_prec,(PBYTE) state );
   }                            /* endswitch                                */
}

/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    ADJUST1                                              */
/*                                                                           */
/*  DESCRIPTIVE NAME:   Adjust 1                                             */
/*                                                                           */
/*  FUNCTION : reshapes the last character from the end of word shape        */
/*             to the initial or mid of word shape. it also returns the      */
/*             state of the machine after the reshaped last character.       */
/*                                                                           */
/*  ENTRY POINT:  adjust1                                                    */
/*      LINKAGE:  CALL NEAR (from pre_edit)                                  */
/*                                                                           */
/*      INPUT: (group_num, char1, char2, state )                             */
/*             group_num    BYTE     - group no. of char1                    */
/*             char1        @CHAR    - character to be adjusted              */
/*             char2        CHAR     - character consulted to adjusted char1 */
/*             state        @BYTE    - ASD machine state after char1.        */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURN VALUE                                             */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:  NONE                                           */
/*                                                                           */
/*    GLOBAL DATA DEFINITION: NONE                                           */
/*                                                                           */
/*    ROUTINES:                                                              */
/*               CLASSIFY()                                                  */
/*               FIND_CHAR()                                                 */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/********************* END OF SPECIFICATIONS *********************************/
void adjust1( ULONG long_group_num, PUCHAR char1, ULONG char2, PBYTE state )
{
  BYTE group_num;

   group_num = (BYTE)long_group_num;

   switch (group_num) {
      case  0 : case  4 : case  5 : case  6 : case  7 : case  8 :
      case 10 : case 11 : case 14 : case 27 :
         *state = BGN_STATE;

      break;
      case 12 :
         find_char( (ULONG)*char1, 12L, 13L, char1 );
                                /*  maps final LAM  to middle LAM           */
         classify( char2, &group_num );

         switch (group_num) {
            case  1 : case  3 : case 13 : case 16 : case 18 : case 19 :
            case 22 : case 23 : case 25 : case 28:
               *state = LAM_MID_STATE;
            break;

            default :
               *state = LAM_FNL_STATE;
         }                      /* endswitch                                */
      break;

      case 15 :
         find_char( (ULONG)*char1, 15L, 16L, char1 );
                                /* e.g : final teh will go to middle teh    */
         *state = MID_STATE;
      break;

      case 17 :
         find_char( (ULONG)*char1, 17L, 18L, char1 );
                                /* e.g : isolated ean will go to initial ean*/
         *state = FNL_STATE;
      break;

      case 20 :
         find_char( (ULONG)*char1, 20L, 19L, char1 );
                                /* e.g : final ean will go to middle ean    */
         *state = MID_STATE;
      break;

      case 21 :
         classify( char2, &group_num );

         switch (group_num) {
            case  1 : case  3 : case 13 : case 16 : case 18 : case 19 :
            case 22 : case 23 : case 25 :
               find_char( (ULONG)*char1, 21L, 23L, char1 );
                                /* e.g : final heh will go to middle heh    */
               *state = MID_STATE;
            break;

            default :
               find_char( (ULONG)*char1, 21L, 22L, char1 );
                                /* e.g : final heh will go to initial heh   */
               *state = FNL_STATE;
         }                      /* endswitch                                */
      break;

      case 24 :
         find_char( (ULONG)*char1, 24L, 25L, char1 );
                                /* e.g : isolated YEH will go to initial YEH*/
         *state = FNL_STATE;
      break;

      case 26 :
         find_char( (ULONG)*char1, 26L, 25L, char1 );
                                /* e.g : final YEH will go to middle YEH    */
         *state = MID_STATE;
      break;

      case 28 :
         *state = MID_STATE;
      break;
   }                            /* endswitch                                */
}

/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    ADJUST2                                              */
/*                                                                           */
/*  DESCRIPTIVE NAME:   ADJUST  2                                            */
/*                                                                           */
/*  FUNCTION : returns the state of the ASD machine from the shapes of the   */
/*             last two characters.                                          */
/*                                                                           */
/*  ENTRY POINT:  adjust2                                                    */
/*      LINKAGE:  CALL NEAR (from pre_edit)                                  */
/*                                                                           */
/*      INPUT: (group_num, char2, state )                                    */
/*           group_num  BYTE      - group no. of char1                       */
/*           char2      CHAR      - second preceding character               */
/*           state      @BYTE     - ASD machine state after char1.           */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURN VALUE                                             */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:  NONE                                           */
/*                                                                           */
/*    GLOBAL DATA DEFINITION: NONE                                           */
/*                                                                           */
/*    ROUTINES:                                                              */
/*               CLASSIFY()                                                  */
/*               FIND_CHAR()                                                 */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/********************* END OF SPECIFICATIONS *********************************/
void adjust2( ULONG long_group_num, ULONG char2, PBYTE state )
{
   BYTE group_num;


   group_num = (BYTE)long_group_num;

   switch (group_num) {

      case  1 : case 16 : case 19 : case 23 :
         *state = MID_STATE;
      break;

      case 18 : case 22 :
         *state = FNL_STATE;
      break;

      case 3 :
         *state = SSSD_STATE;
      break;

      case 13 :
         classify( char2, &group_num );

         switch (group_num) {
            case  1 : case  3 : case 13 : case 16 : case 18 : case 19 :
            case 22 : case 23 : case 25 :
               *state = LAM_MID_STATE;
            break;

            default :
               *state = LAM_FNL_STATE;
         }                      /* endswitch                                */
      break;

      case  9 : case 25 :
         classify( char2, &group_num );

         switch (group_num) {
            case  1 : case  3 : case 13 : case 16 : case 18 : case 19 :
            case 22 : case 23 : case 25 : case 9  : case 28 :
               *state = MID_STATE;
            break;

            default :
               *state = FNL_STATE;
         }                      /* endswitch                                */
      break;

      case 28 :
         *state = MID_STATE;
      default : ;
   }                            /* endswitch                                */
}


static unsigned char special[SPECIALNO]={ 0x99, 0x9A, 0x9D, 0x9E, 0xF9, 0xFA };

static char basemap[128] = {
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0xC3,0xC3,0x9B,0x9C,0xC7,0xC7,0x20,
0xA0,0xA1,0xC2,0xA3,0xA4,0xC3,0xA6,0xA7,0xC7,0xC8,0xCA,0xCB,0xAC,0xCC,0xCD,0xCE,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xE1,0xBB,0xD3,0xD4,0xD5,0xBF,
0xC0,0xC1,0xC2,0xC3,0xC4,0xD9,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xD9,
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xD6,0xD9,0xDA,0xDA,0xE5,
0xF1,0xF1,0xE6,0xE7,0xE7,0xE9,0xEA,0xDA,0xE2,0xC2,0xC2,0xE4,0xE3,0xEA,0xFE,0xFF
};

static char initialmap[128] = {
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x99,0x9B,0x9C,0x9D,0x9D,0x20,
0xA0,0xA1,0xC2,0xA3,0xA4,0xC3,0xA6,0xA7,0xC7,0xC8,0xCA,0xCB,0xAC,0xCC,0xCD,0xCE,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xE1,0xBB,0xD3,0xD4,0xD5,0xBF,
0xC0,0xC1,0xC2,0xC3,0xC4,0xD9,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xD3,0xDD,0xDE,0xD9,
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xD6,0xD9,0xDA,0xDA,0xE5,
0xF1,0xF1,0xE6,0xE7,0xE7,0xE9,0xEA,0xDA,0xE2,0xF9,0xF9,0xE4,0xE3,0xEA,0xFE,0xFF
};

static char middlemap[128] = {
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x9A,0x9A,0x9B,0x9C,0x9E,0x9E,0x20,
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xC8,0xCA,0xCB,0xAC,0xCC,0xCD,0xCE,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xE1,0xBB,0xD3,0xD4,0xD5,0xBF,
0xC0,0xC1,0xA2,0xA5,0xC4,0xEC,0xC6,0xA8,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xEC,0xF7,0xDB,0xDC,0xDD,0xDE,0xEC,
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xF4,0xE8,0xF5,0xEA,0xD6,0xEC,0xF7,0xF7,0xE5,
0xF0,0xF0,0xE6,0xF4,0xF4,0xF5,0xEA,0xF7,0xE2,0xFA,0xFA,0xE4,0xE3,0xEA,0xFE,0xFF
};

static char finalmap[128] = {
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x9A,0x9A,0x9B,0x9C,0x9E,0x9E,0x20,
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
0xC0,0xC1,0xA2,0xA5,0xC4,0xC5,0xF5,0xA8,0xA9,0xC9,0xAA,0xAB,0xAD,0xAE,0xAF,0xCF,
0xD0,0xD1,0xD2,0xBC,0xBD,0xBE,0xEB,0xD7,0xD8,0xC5,0xED,0xDB,0xDC,0xDD,0xDE,0xC5,
0xE0,0xBA,0xF8,0xFC,0xFB,0xEF,0xF2,0xF3,0xE8,0xF5,0xF6,0xEB,0xC5,0xED,0xED,0xEF,
0xF1,0xF1,0xF2,0xF3,0xF3,0xF5,0xF6,0xED,0xF8,0xFA,0xFA,0xFB,0xFC,0xF6,0xFE,0xFF
};

static char isolatedmap[128] = {
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x99,0x9B,0x9C,0x9D,0x9D,0x20,
0xA0,0xA1,0xC2,0xA3,0xA4,0xC3,0xA6,0xA7,0xC7,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
0xC0,0xC1,0xC2,0xC3,0xC4,0xDF,0xE9,0xC7,0xA9,0xC9,0xAA,0xAB,0xAD,0xAE,0xAF,0xCF,
0xD0,0xD1,0xD2,0xBC,0xBD,0xBE,0xEB,0xD7,0xD8,0xDF,0xEE,0xDB,0xDC,0xDD,0xDE,0xDF,
0xE0,0xBA,0xF8,0xFC,0xFB,0xEF,0xF2,0xF3,0xE8,0xE9,0xFD,0xEB,0xDF,0xEE,0xEE,0xEF,
0xF1,0xF1,0xF2,0xF3,0xF3,0xE9,0xFD,0xEE,0xF8,0xF9,0xF9,0xFB,0xFC,0xFD,0xFE,0xFF
};

/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    DESHAPE                                              */
/*                                                                           */
/*  DESCRIPTIVE NAME:   De-shapes a string of characters                     */
/*                                                                           */
/*  FUNCTION : The deshape function deshapes a string of characters to       */
/*             base, initial, middle, final or isolated shapes according     */
/*             to the Bidi attributes.                                       */
/*                                                                           */
/*  ENTRY POINT:  deshape                                                    */
/*      LINKAGE:  CALL NEAR (from pre_deshape)                               */
/*                                                                           */
/*      INPUT:  (@source, @target, length, attribute)                        */
/*            source     @OTHER  - Source buffer                             */
/*            target     @OTHER  - Target buffer                             */
/*            length     DWORD   - Length of the source and the target       */
/*            attribute  DWORD   - Bidi attributes                           */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURNED VALUE                                           */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:                                                 */
/*        DWORD  i           - main counter for the source and target buffer */
/*        DWORD  direction   - Direction of scanning the buffer according    */
/*                             to the orientation.                           */
/*        WORD   csd         - To hold the value of the csd byte in the Bidi */
/*                             attributes                                    */
/*        DWORD  limit       - To indicate the boundary of the integer 'i'   */
/*                                                                           */
/*    GLOBAL DATA DEFINITION:                                                */
/*        CHAR  basemap       - Array containing the base shape of chars     */
/*        CHAR  initialmap    - Array containing the initial shapes of chars */
/*        CHAR  middlemap     - Array containing the middle shapes of chars  */
/*        CHAR  finalmap      - Array containing the final shapes of chars   */
/*        CHAR  isolatedmap   - Array containing the isolated shapes of chars*/
/*                                                                           */
/*    ROUTINES:   getbase()   - Called when deshaping to base shape is       */
/*                              required                                     */
/*                deshape_int_mid()                                          */
/*                            - Called when either deshaping to initial or   */
/*                              or middle shape is required                  */
/*                deshape_iso_fin()                                          */
/*                            - Called when either deshaping to isolated or  */
/*                              or final shape is required                   */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/
void   deshape ( unsigned char *source, char *target, unsigned long length,
                 unsigned long attribute )

{
 int  csd;                      /* to hold the csd byte of the Bidi Atts    */

 long i,                        /* main counter of the blocks               */

      direction,                /* 1 when orientation is right to left      */
                                /* -1 when orientation is left to right     */

      limit;                    /* maximum bound of i                       */

  csd = (int)attribute & 0x00FF;
  direction = (attribute >> 16) & 0x00FF;
                                /* direction now holds the orientation value*/

  if (direction == 0)           /* i.e orientation is left to right         */
   {
      direction = -1;
      i = length - 1;
      limit = -1;
   }
  else
   {
      direction = 1;
      i = 0;
      limit = length;
   }
  switch (csd )
   {
     case BASE :                /* case of deshaping to base shapes         */
       getbase( source, target, i, limit, direction );
     break;

     case INITIAL:              /* case of deshaping to initial shapes      */
       deshape_int_mid( source, target, i, limit, direction, initialmap );
     break;

     case MIDDLE:               /* case of deshaping to middle shapes       */
       deshape_int_mid( source, target, i, limit, direction, middlemap );
     break;

     case FINAL:                /* case of deshaping to final shapes        */
       deshape_iso_fin( source, target, i, limit, direction, finalmap );
     break;

     case ISOLATED:             /* case of deshaping to isolated shapes     */
       deshape_iso_fin( source, target, i, limit, direction, isolatedmap );
     break;
    }                           /* endswitch                                */

}

/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    GETBASE                                              */
/*                                                                           */
/*  DESCRIPTIVE NAME:   Gets the base shape of a string of characters        */
/*                                                                           */
/*  FUNCTION : The getbase function maps a string of characters to their     */
/*             base shape font points.                                       */
/*             The base shape of the LAMALEF character is two characters     */
/*             a LAM and an ALEF in the succeeding position.                 */
/*                                                                           */
/*  ENTRY POINT:  getbase                                                    */
/*      LINKAGE:  CALL NEAR (from deshape)                                   */
/*                                                                           */
/*      INPUT: (@source, @target, i, limit, direction)                       */
/*            source     @OTHER  - Source buffer                             */
/*            target     @OTHER  - Target buffer                             */
/*            i          DWOED   - The initial value of the buffer counter   */
/*            limit      DWORD   - The final value of the buffer counter     */
/*            direction  DWORD   - To increment/decrement the buffer counter */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURNED VALUE                                           */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES:                                                     */
/*    LOCAL DATA DEFINITION:                                                 */
/*        WORD   j           - Counter for the global array 'special'        */
/*        WORD   lamalef     - True when a LAMALEF is found                  */
/*                                                                           */
/*    GLOBAL DATA DEFINITION:                                                */
/*        CHAR   special     - Array containing the ASCII of LAMALEF chars   */
/*                                                                           */
/*    ROUTINES: NONE                                                         */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/
void getbase(unsigned char *source, char *target, long i, long limit,
             long direction )

{
  int
     j,                         /* counter for the special characters array */

     lamalef;                   /* true when an lamalef character is found  */
  do
   {
    j = 0;
    while (!(lamalef = (source[i] == special[j])) && (++j < SPECIALNO));
                                /* find if the character is a LAMALEF       */
      if (lamalef)
       {
        if (i+direction!=limit)
                                /* if we can write the first succeeding char*/
        target[i+direction] = basemap[source[i]-0x80];
                                /* write the proper ALEF in the succeeding  */
                                /* character position                       */
        target[i] = LAM;
                                /* write LAM in the current position        */
        i += direction;
       }
      else                      /* if the character is not a LAMALEF        */
        {
         target[i] = (source[i] <= 0x7F) ? source[i] : basemap[source[i]-0x80];
                                /* map the character to its base shape      */
        }
      if(i!=limit)
      i += direction;
    }
    while ( (i != limit) );
}

/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    DESHAPE_INT_MID                                      */
/*                                                                           */
/*  DESCRIPTIVE NAME:   Deshapes a string of characters to middle or initial */
/*                      shape                                                */
/*                                                                           */
/*  FUNCTION : The deshape_int_mid function maps a string of characters      */
/*             to middle or initial shape according to the mapping array     */
/*             passed                                                        */
/*                                                                           */
/*  ENTRY POINT:  deshape_int_mid                                            */
/*      LINKAGE:  CALL NEAR (from deshape)                                   */
/*                                                                           */
/*      INPUT: (@source, @target, i, limit,direction, @map)                  */
/*            source     @OTHER  - Source buffer                             */
/*            target     @OTHER  - Target buffer                             */
/*            i          DWORD   - The initial value of the buffer counter   */
/*            limit      DWORD   - The final value of the buffer counter     */
/*            direction  DWORD   - To increment/decrement the buffer counter */
/*            map        @OTHER  - The mapping array                         */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURNED VALUE                                           */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/
void deshape_int_mid( unsigned char *source, char *target, long i, long limit,
                      long direction, char *map  )
{

   do
    {
      target[i] = (source[i] <= 0x7F) ? source[i] : map[source[i]-0x80];
                                /* map the character to initial or middle   */
                                /* shape according to the mapping array     */
                                /* passed                                   */
      i += direction;
    }
   while ( i != limit );
}

/*********************** START OF SPECIFICATIONS *****************************/
/*  SUBROUTINE NAME:    DESHAPE_ISO_FIN                                      */
/*                                                                           */
/*  DESCRIPTIVE NAME:   Deshapes a string of characters to isolated or final */
/*                      shape                                                */
/*                                                                           */
/*  FUNCTION : The deshape_iso_fin function maps a string of characters      */
/*             to isolated or final shape according to the mapping array     */
/*             passed                                                        */
/*             The YEH-HAMZA will be treated as two characters (ALEF MAKSURA */
/*             and HAMZA) if it is followed by a blank.                      */
/*                                                                           */
/*  ENTRY POINT:  deshape_iso_fin                                            */
/*      LINKAGE:  CALL NEAR (from deshape)                                   */
/*                                                                           */
/*      INPUT: (@source, @target, i, limit, direction, @map )                */
/*           source     @CHAR   - Source buffer                              */
/*           target     @CHAR   - Target buffer                              */
/*           i          DWORD   - The initial value of the buffer counter    */
/*           limit      DWORD   - The final value of the buffer counter      */
/*           direction  DWORD   - To increment/decrement the buffer counter  */
/*           map        @CHAR   - The mapping array                          */
/*                                                                           */
/*  EXIT-NORMAL: NO RETURNED VALUE                                           */
/*                                                                           */
/*  EXIT-ERROR: NONE                                                         */
/*                                                                           */
/*  INTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/*  EXTERNAL REFERENCES: NONE                                                */
/*                                                                           */
/************************* END OF SPECIFICATIONS *****************************/
void deshape_iso_fin( unsigned char *source, char *target, long i, long limit,
                      long direction, char *map )
{
  do
    {
     if (source[i] == YEH_HAMZA_CH)
                                /* if the character is a YEH_HAMZA_CH       */
       {
        if ( ((i+direction)!= limit) && (source[i+direction] == 0x20) )
                                /* if the succeeding character lies inside  */
                                /* the buffer and it is a BLANK             */
         {
           target[i] = map[source[i]-0x80];
                                /* map current to ALEF_MAKSURA              */
           target[i+direction] = 0xC1;
                                /* map the succeeding to HAMZA              */
           i += direction ;
         }
        else
           target[i] = YEH_HAMZA_CH;
                                /* write the character as is into target    */
       }
     else                       /* the character is not a YEH_HAMZA_CH      */
       target[i] = (source[i] <= 0x7F) ? source[i] : map[source[i]-0x80];
                                /* map the character to isolated or final   */
                                /* shape according to the mapping array     */
                                /* passed                                   */
     i += direction;
    }
  while ( i != limit );
}

