#include <os2.h>
#include "bdcalls.h"
#include "bdatt.h"
#include "blkapifn.h"
#define  BidiAbs(X)   (((X)>=0) ? (X) : ((X) * -1))

/* Function prototypes */
void InvertOverlapping (char far *source,
                        unsigned long length ,
                        unsigned long increment);

void InvertDisjoint (char far * source ,
                     char far * target,
                     unsigned long length  ,
                     unsigned long increment);

/****************** START OF SPECIFICATIONS ****************************/
/*                                                                     */
/* SUBROUTINE  NAME: NLSINVERSESTRING                                  */
/*                                                                     */
/*  COPYRIGHT: (c) IBM Corp. 1989                                      */
/*                                                                     */
/* DESCRIPTIVE NAME: Inverts a string and places it at a specified     */
/*                   address                                           */
/*                                                                     */
/* FUNCTION: NlsInverseString inverts a string whose address is        */
/*           Source, has Length characters and a cell size of          */
/*           Increment. The inversion process works such that the      */
/*           string ,inverted, is placed starting at location Target.  */
/*           The Source string is unchanged unless there is an         */
/*           overlap of the Source and Target strings. Inversion       */
/*           works on cells not on individual characters i.e.          */
/*           elements   within one cell are not inverted on their      */
/*           own.                                                      */
/*                                                                     */
/* ENTRY POINT:  NlsInverseString                                      */
/*     LINKAGE:  CALL FAR (dynamic link API)                           */
/*                                                                     */
/* INPUT:  (Source,Target,Length,Increment)                            */
/*         @Source   CHAR    -  pointer to the source string           */
/*         @Target   CHAR    -  pointer to the target string           */
/*         Length    DWORD   -  length of the source/target string     */
/*         Increment DWORD   -  cell size                              */
/*                                                                     */
/* EXIT-NORMAL:   RC=0                                                 */
/*                                                                     */
/* EXIT-ERROR:    RC = ERROR_BIDI_BAD_LENGTH     - invalid length      */
/*                RC = ERROR_BIDI_BAD_INCREMENT  - invalid increment   */
/*                                                                     */
/* SIDE EFFECTS:  The source string remains unchanged after inversion  */
/*                unless an overlap has occurred. In this case only    */
/*                the overlapping portion changes.                     */
/*                                                                     */
/* INTERNAL REFERENCES:                                                */
/*   LOCAL DATA DEFINITION:                                            */
/*       DWORD  NoOverLapLen    - non-overlapping length               */
/*              OverlapLen      - overlapping length                   */
/*              Shift           - distance between the start of        */
/*                                Source or Target (depending on       */
/*                                the kind of overlap) and the         */
/*                                nearest cell edge.                   */
/*              k               - loop counter                         */
/*              RC              - return code                          */
/*                                                                     */
/*       CHAR   @i                        - pointer to a location      */
/*                                          within the Source string   */
/*              @j                        - pointer to a location      */
/*                                          within target string       */
/*              @FromInvertDisjoint       - pointer to the non-        */
/*                                          overlapping portion of     */
/*                                          the Source string          */
/*              @ToInvertDisjoint         - pointer to the non-        */
/*                                          overlapping portion of     */
/*                                          the Target string          */
/*              @StartInvertOverlapping   - pointer to the buffer      */
/*                                          which is to be reversed.   */
/*                                          This pointer is always     */
/*                                          within the scope of the    */
/*                                          target string              */
/*                                                                     */
/*   GLOBAL DATA DEFINITION:    NONE                                   */
/*   ROUTINES:                  RCLenInc  - performs error checking    */
/*                                          on Length and Increment    */
/*                                          and returns appropriate    */
/*                                          return codes               */
/* EXTERNAL REFERENCES:                                                */
/*   ROUTINES:                  NONE                                   */
/*                                                                     */
/********************* END OF SPECIFICATIONS ***************************/
extern USHORT far pascal _loadds NlsInverseString ( PCHAR Source,
                                                    PCHAR Target,
                                                    ULONG Length,
                                                    ULONG Increment)

/* NlsInverseString inverts a string whose address is Source, has Length   */
/* characters and a cell size of Increment.  The inversion process works   */
/* such that the string ,inverted, is placed starting at location Target.  */
/* The Source string is unchanged unless there is an overlap of the Source */
/* and Target strings.  Inversion works on cells not on individual         */
/* characters i.e.  characters within one cell are not inverted on their   */
/* own.                                                                    */
{
   unsigned long  NoOverlapLen,           /*  non-overlapping Length          */
                  OverlapLen,             /*  overlapping Length              */
                  Shift,                  /*  distance between the start of   */
                                          /*  Source or Target (depending on  */
                                          /*  the kind of overlap) and the    */
                                          /*  nearest cell edge.              */
                  k;                      /*  loop counter                    */
   USHORT         RC;                     /*  return code                     */

            char far *i,                     /* pointer to a location within  */
                                             /* the Source string             */

                  far *j,                    /* pointer to a location within  */
                                             /* the Target string             */

                  far *FromInvertDisjoint,   /* pointer to the non-           */
                                             /* overlapping portion of        */
                                             /* the Source string             */

                  far *ToInvertDisjoint,     /* pointer to the non-           */
                                             /* overlapping portion of the    */
                                             /* Target string                 */

                  far *StartInvertOverlapping; /* pointer to the buffer         */
                                             /* which is to be reversed.      */
                                             /* This pointer is always        */
                                             /* within the scope of the       */
                                             /* Target string                 */

                        /****************************/
                        /* Start of Error Checking  */
                        /****************************/

   if ((RC=(USHORT)RCLenInc(Length,Increment))!=0)
                                         /* checking for Length and Increment */
        return RC;

                        /****************************/
                        /* End  of  Error Checking  */
                        /****************************/

   if (Source == Target)                     /* Source and Target point to    */
                                             /* the same location             */

      InvertOverlapping(Source,Length,Increment); /* invert the Source in     */
                                                  /* place                    */
     else {                                  /* Source and Target point to    */
                                             /* different locations           */
       if ( ((long)Source/65536)!=((long)Target/65536) )
         InvertDisjoint(Source,Target,Length,Increment);
       else {
           NoOverlapLen = BidiAbs(Source-Target);
           if (NoOverlapLen>=Length)              /* Source and Target disjoint    */
              InvertDisjoint(Source,Target,Length,Increment);
             else {                               /* Source and Target overlapping */
              Shift = NoOverlapLen % Increment;
              NoOverlapLen-=Shift;
              OverlapLen = Length - NoOverlapLen;
              if (Source<Target) {
                 StartInvertOverlapping = Target;
                 FromInvertDisjoint     = Source;
                 ToInvertDisjoint       = Target + Length - NoOverlapLen;
                 if (Shift!=0)
                    for (i=Source+Length-1,j=StartInvertOverlapping+OverlapLen-1,
                         k=0; k<OverlapLen;i--,j--,k++)
                            *j = *i;
              } else {
                 StartInvertOverlapping = Source - Shift;
                 FromInvertDisjoint     = Source + OverlapLen;
                 ToInvertDisjoint       = Target;
                 if (Shift != 0)
                    for (i=Source,j=StartInvertOverlapping,k=0;
                         k<OverlapLen;i++,j++,k++)
                            *j = *i;
              }
              InvertOverlapping (StartInvertOverlapping,OverlapLen,Increment);
              if (Shift<BidiAbs(Source-Target))
                InvertDisjoint    (FromInvertDisjoint,ToInvertDisjoint,
                                   NoOverlapLen, Increment );
           }
        }
   }
   return(0);
}

/******************** START OF SPECIFICATIONS **************************/
/*                                                                     */
/* SUBROUTINE  NAME: INVERTOVERLAPPING                                 */
/*                                                                     */
/* FUNCTION: reverses the order of cells in a Source string by         */
/*           replacing every 2 cells equidistant from the 2 ends       */
/*           of the string by each other.                              */
/*                                                                     */
/* ENTRY POINT:  InvertOverlapping                                     */
/*     LINKAGE:  CALL NEAR (from NlsInverseString)                     */
/*                                                                     */
/* INPUT:    (StartOverlap,LengthOverlap,Increment)                    */
/*           @StartOverlap   CHAR   -  pointer to start of overlap     */
/*           LengthOverlap   DWORD  -  length of overlapped part       */
/*           Increment       DWORD  -  cell size                       */
/*                                                                     */
/* EXIT-NORMAL:   NONE                                                 */
/*                                                                     */
/* EXIT-ERROR:    NONE                                                 */
/*                                                                     */
/* INTERNAL REFERENCES:                                                */
/*   LOCAL DATA DEFINITION:                                            */
/*       DWORD  i              -loop counter                           */
/*                                                                     */
/*       CHAR   @start         -pointer to a cell, starting from       */
/*                              the first cell                         */
/*              @end           -pointer to a cell, starting from       */
/*                              the last cell                          */
/*              TempByte       -a temporary character                  */
/*                                                                     */
/*   GLOBAL DATA DEFINITION:    NONE                                   */
/*   ROUTINES:                  NONE                                   */
/*                                                                     */
/* EXTERNAL REFERENCES:                                                */
/* ROUTINES:                  NONE                                     */
/*                                                                     */
/********************* END OF SPECIFICATIONS ***************************/
void InvertOverlapping (char far *source,
                        unsigned long length ,
                        unsigned long increment)
{
   char far *start,               /* location of a cell from start of string */
        far *end;                 /* location of a cell from end   of string */
   char TempByte;                 /* temporary byte */
   unsigned long i;               /* counter        */

   /************************** Initialisation ****************************/
   start =  source;
   end = start + length - increment;
   /********************** End of Initialisation *************************/

   /* start copying cells, crosswise =====>> INVERTING the cells */
   do
    {
      for (i=0;i<increment;i++ ) {   /* copy the cell starting at start to */
         TempByte = *(start+i);      /* the cell starting at end           */
         *(start+i) = *(end+i);
         *(end+i)   = TempByte;
      }
      start  += increment;
      end    -= increment;
    }
   while (start<end);
}
/******************** START OF SPECIFICATIONS **************************/
/*                                                                     */
/* SUBROUTINE  NAME: INVERTDISJOINT                                    */
/*                                                                     */
/* FUNCTION: This is called whenever the Source and the Target are     */
/*           totally disjoint or when an overlap occurs and the        */
/*           non-overlapping portion of the Source is to be inverted.  */
/*           InvertDisjoint copies every 2 cells equidistant from      */
/*           the 2 ends of the Source string to the same positions     */
/*           in the Target string after exchanging them.               */
/*                                                                     */
/* ENTRY POINT:  InvertDisjoint                                        */
/*     LINKAGE:  CALL NEAR (from NlsInverseString)                     */
/*                                                                     */
/* INPUT:    (SourceDisjoint,TargetDisjoint,LengthDisjoint,Increment)  */
/*           @SourceDisjoint  CHAR  - pointer to a source disjoint     */
/*                                    string                           */
/*           @TargetDisjoint  CHAR  - pointer to a disjoint Target     */
/*                                    string                           */
/*           LengthDisjoint   DWORD - length of string                 */
/*           Increment        DWORD - cell size                        */
/*                                                                     */
/* EXIT-NORMAL:   NONE                                                 */
/*                                                                     */
/* EXIT-ERROR:    NONE                                                 */
/*                                                                     */
/* INTERNAL REFERENCES:                                                */
/*   LOCAL DATA DEFINITION:                                            */
/*                                                                     */
/*       CHAR   @SourceStart         -pointer to a cell, starting from */
/*                                    the first cell in source         */
/*              @SourceEnd           -pointer to a cell, starting from */
/*                                    the last cell in source          */
/*              @TargetStart         -pointer to a cell, starting from */
/*                                    the first cell in Target         */
/*              @TargetEnd           -pointer to a cell, starting from */
/*                                    the last cell in Target          */
/*       DWORD  i                    -loop counter                     */
/*              count                -counter for no. of inversions    */
/*              NCells               -no. of cells in source/Target    */
/*                                                                     */
/*   GLOBAL DATA DEFINITION:    NONE                                   */
/*   ROUTINES:                  NONE                                   */
/*                                                                     */
/* EXTERNAL REFERENCES:                                                */
/* ROUTINES:                  NONE                                     */
/*                                                                     */
/********************* END OF SPECIFICATIONS ***************************/
void InvertDisjoint (char far * source ,
                     char far * target,
                     unsigned long length  ,
                     unsigned long increment)

{
   char far *TargetStart,        /* location of a cell from start of target */
        far *TargetEnd  ,        /* location of a cell from end   of target */
        far *SourceEnd  ,        /* location of a cell from start of source */
        far *SourceStart;        /* location of a cell from end   of source */

   unsigned long  i    ,         /* counter and array index                 */
                  count,         /* counter of number of inversions         */
                  NCells;        /* no. of cells in source                  */

   /********************* Variables Initialisation **************************/
   SourceStart = source;
   SourceEnd   = source + length - increment;
   TargetStart = target;
   TargetEnd   = target + length - increment;
   NCells      = length / increment;  /* no. of cells */
   count       = (NCells/2)  + (NCells % 2);
   /********************* End of Variables Initialisation ********************/
   do {
       for (i=0;i<increment;i++) {  /* place the cells starting at SourceStart
                                       and SourceEnd,exchanged, in TargetEnd
                                       and TargetStart                       */
         *(TargetStart+i) = *(SourceEnd+i);
         *(TargetEnd+i)   = *(SourceStart+i);
       }
       /*********** decrement pointers by cell size ***********/
       SourceStart += increment;
       TargetEnd   -= increment;
       TargetStart += increment;
       SourceEnd   -= increment;
       count--;            /* one less inversion */
   } while (count >0);
}
