/* $XConsortium: StringNext.c /main/6 1996/06/11 17:23:20 pascale $ */
/*
 * @OPENGROUP_COPYRIGHT@
 *  COPYRIGHT NOTICE
 *  Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
 *  Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
 *  ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
 *  the full copyright text.
 *  
 *  This software is subject to an open license. It may only be
 *  used on, with or for operating systems which are themselves open
 *  source systems. You must contact The Open Group for a license
 *  allowing distribution and sublicensing of this software on, with,
 *  or for operating systems which are not Open Source programs.
 *  
 *  See http://www.opengroup.org/openmotif/license for full
 *  details of the license agreement. Any use, reproduction, or
 *  distribution of the program constitutes recipient's acceptance of
 *  this agreement.
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
 *  PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 *  WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
 *  OR FITNESS FOR A PARTICULAR PURPOSE
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
 *  NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
 *  EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGES.
 */
/*
 * HISTORY
 */
#include <testlib.h>

/*
 *  Type definitions
 */
typedef struct _Components {
	XmStringComponentType	type;
	unsigned int		length;
	XtPointer		value;
} Components;

typedef struct _Segments {
	char 			*text;
	char			*tag;
	XmTextType              type;
	XmStringTag             *rendition_tags;
	unsigned int		tag_count;
	XmStringDirection	direction;
	XmDirection		push_before;
	Boolean			pop_after;
	Boolean			separator;
	unsigned char		num_tabs; 	
} Segments;
	

/*
 *  Global variables.
 */
#define NUM_COMPONENTS 10

Components components[NUM_COMPONENTS] = {
    { XmSTRING_COMPONENT_RENDITION_BEGIN, 0, (XtPointer)"render_tag" },
    { XmSTRING_COMPONENT_DIRECTION, 0, (XtPointer)0 },
    { XmSTRING_COMPONENT_TEXT, 0, (XtPointer)"Howdy" },
    { XmSTRING_COMPONENT_SEPARATOR, 0, (XtPointer)0 },
    { XmSTRING_COMPONENT_TAB, 0, (XtPointer)0 },  
    { XmSTRING_COMPONENT_DIRECTION, 0, (XtPointer)0 },
    { XmSTRING_COMPONENT_TEXT, 0, (XtPointer)"Doody" },
    { XmSTRING_COMPONENT_SEPARATOR, 0, (XtPointer)0 },
    { XmSTRING_COMPONENT_RENDITION_END, 0, (XtPointer)"render_tag" },
    { XmSTRING_COMPONENT_END, 0, (XtPointer)0 }};

#define NUM_SEGMENTS 4

Segments segments[NUM_SEGMENTS] = {
    { "One", XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, (XmStringTag *)0,
      0, XmSTRING_DIRECTION_L_TO_R, XmLEFT_TO_RIGHT, False, True,
      2 },
    { "Two", XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, (XmStringTag *)0,
      0, XmSTRING_DIRECTION_R_TO_L, XmLEFT_TO_RIGHT, False, True,
      2 },
    { "Three", XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, (XmStringTag *)0,
      0, XmSTRING_DIRECTION_R_TO_L, (XmDirection)0, True, True,
      1 },
    { "Four", XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, (XmStringTag *)0,
      0, XmSTRING_DIRECTION_L_TO_R, XmRIGHT_TO_LEFT, False, False,
      0 }};

#define NUM_ORDERED_COMPONENTS 11
#define NUM_ORDERED_STRINGS 3

Components ordered_comp[NUM_ORDERED_STRINGS][NUM_ORDERED_COMPONENTS] = {
   {
    { XmSTRING_COMPONENT_LAYOUT_PUSH, 0, (XtPointer)"XmLEFT_TO_RIGHT" }, 
    { XmSTRING_COMPONENT_RENDITION_BEGIN, 0, (XtPointer)"render_tag1" }, 
    { XmSTRING_COMPONENT_RENDITION_BEGIN, 0, (XtPointer)"render_tag2" }, 
    { XmSTRING_COMPONENT_TAG, 0, (XtPointer)XmSTRING_ISO8859_1 }, 
    { XmSTRING_COMPONENT_TAB, 0, (XtPointer)NULL }, 
    { XmSTRING_COMPONENT_DIRECTION, 0, (XtPointer)"XmSTRING_DIRECTION_L_TO_R" },
    { XmSTRING_COMPONENT_TEXT, 0, (XtPointer)"Hello World" }, 
    { XmSTRING_COMPONENT_RENDITION_END, 0, (XtPointer)"render_tag2 " }, 
    { XmSTRING_COMPONENT_RENDITION_END, 0, (XtPointer)"render_tag1 " }, 
    { XmSTRING_COMPONENT_LAYOUT_POP, 0, (XtPointer)NULL }, 
    { XmSTRING_COMPONENT_SEPARATOR, 0, (XtPointer)NULL } 
   },
   {
    { XmSTRING_COMPONENT_LAYOUT_PUSH, 0, (XtPointer)"XmLEFT_TO_RIGHT" }, 
    { XmSTRING_COMPONENT_RENDITION_BEGIN, 0, (XtPointer)"render_tag2" }, 
    { XmSTRING_COMPONENT_RENDITION_BEGIN, 0, (XtPointer)"render_tag1" }, 
    { XmSTRING_COMPONENT_TAB, 0, (XtPointer)NULL }, 
    { XmSTRING_COMPONENT_DIRECTION, 0, (XtPointer)"XmSTRING_DIRECTION_R_TO_L" },
    { XmSTRING_COMPONENT_LOCALE_TEXT, 0, (XtPointer)"Hello World" }, 
    { XmSTRING_COMPONENT_DIRECTION, 0, (XtPointer)"XmSTRING_DIRECTION_L_TO_R" },
    { XmSTRING_COMPONENT_RENDITION_END, 0, (XtPointer)"render_tag2" },
    { XmSTRING_COMPONENT_LAYOUT_POP, 0, (XtPointer)NULL }, 
    { XmSTRING_COMPONENT_SEPARATOR, 0, (XtPointer)NULL }, 
    { XmSTRING_COMPONENT_RENDITION_END, 0, (XtPointer)"render_tag1" }
   },
   {
    { XmSTRING_COMPONENT_LAYOUT_PUSH, 0, (XtPointer)"XmRIGHT_TO_LEFT" }, 
    { XmSTRING_COMPONENT_RENDITION_BEGIN, 0, (XtPointer)"render_tag2" }, 
    { XmSTRING_COMPONENT_DIRECTION, 0, (XtPointer)"XmSTRING_DIRECTION_R_TO_L" },
    { XmSTRING_COMPONENT_WIDECHAR_TEXT, 0, "Hi " }, 
    { XmSTRING_COMPONENT_RENDITION_END, 0, (XtPointer)"render_tag2" }, 
    { XmSTRING_COMPONENT_RENDITION_BEGIN, 0, (XtPointer)"render_tag1" }, 
    { XmSTRING_COMPONENT_TAB, 0, (XtPointer)NULL }, 
    { XmSTRING_COMPONENT_DIRECTION, 0, (XtPointer)"XmSTRING_DIRECTION_L_TO_R" },
    { XmSTRING_COMPONENT_TEXT, 0, "World" }, 
    { XmSTRING_COMPONENT_RENDITION_END, 0, (XtPointer)"render_tag1" },
    { XmSTRING_COMPONENT_LAYOUT_POP, 0, (XtPointer)NULL }
   }};

#define NUM_CANONICAL_COMPONENTS 13

XmStringComponentType canonical_order[NUM_CANONICAL_COMPONENTS] = { 
  XmSTRING_COMPONENT_LAYOUT_PUSH,
  XmSTRING_COMPONENT_RENDITION_BEGIN,
  XmSTRING_COMPONENT_TAG,
  XmSTRING_COMPONENT_LOCALE,
  XmSTRING_COMPONENT_TAB,
  XmSTRING_COMPONENT_DIRECTION,
  XmSTRING_COMPONENT_TEXT,
  XmSTRING_COMPONENT_LOCALE_TEXT,
  XmSTRING_COMPONENT_WIDECHAR_TEXT,
  XmSTRING_COMPONENT_RENDITION_END,
  XmSTRING_COMPONENT_LAYOUT_POP,
  XmSTRING_COMPONENT_SEPARATOR,
  XmSTRING_COMPONENT_END };
  
#define DISPLAY_WIDTH 250
#define DISPLAY_HEIGHT 50
        
XmStringDirection     stringdir_ltor = XmSTRING_DIRECTION_L_TO_R;
XmStringDirection     stringdir_rtol = XmSTRING_DIRECTION_R_TO_L;
XmDirection           dir_ltor = XmLEFT_TO_RIGHT; 
XmDirection           dir_rtol = XmRIGHT_TO_LEFT; 
XmString              draw_string;
Widget                bboard, drawingArea;
GC                    gc;
XGCValues             gcv;
XFontStruct           *fontStruct;
XmRenderTable         renderTable;

void 
DrawString( Widget w, XtPointer client_data, XtPointer call_data )
{

    /*  Display XmString with tabs and renditions. */
    XmStringDrawImage( display, XtWindow( drawingArea ), renderTable, 
                       draw_string, gc, 0, 0, DISPLAY_WIDTH, 
                       XmALIGNMENT_BEGINNING,
                       XmSTRING_DIRECTION_L_TO_R, (XRectangle *)0 );
}

static char * 
CvtCompTypeToString( XmStringComponentType comp_type )
{
   char *comp_string;

      switch( comp_type )
      {
         case XmSTRING_COMPONENT_DIRECTION:
              comp_string = "XmSTRING_COMPONENT_DIRECTION";
              break; 
         case XmSTRING_COMPONENT_END:
              comp_string = "XmSTRING_COMPONENT_END";
              break; 
         case XmSTRING_COMPONENT_LAYOUT_POP:
              comp_string = "XmSTRING_COMPONENT_LAYOUT_POP";
              break; 
         case XmSTRING_COMPONENT_LAYOUT_PUSH:
              comp_string = "XmSTRING_COMPONENT_LAYOUT_PUSH";
              break; 
         case XmSTRING_COMPONENT_LOCALE:
              comp_string = "XmSTRING_COMPONENT_LOCALE";
              break; 
         case XmSTRING_COMPONENT_LOCALE_TEXT:
              comp_string = "XmSTRING_COMPONENT_LOCALE_TEXT";
              break; 
         case XmSTRING_COMPONENT_RENDITION_BEGIN:
              comp_string = "XmSTRING_COMPONENT_RENDITION_BEGIN";
              break; 
         case XmSTRING_COMPONENT_RENDITION_END:
              comp_string = "XmSTRING_COMPONENT_RENDITION_END";
              break; 
         case XmSTRING_COMPONENT_SEPARATOR:
              comp_string = "XmSTRING_COMPONENT_SEPARATOR";
              break; 
         case XmSTRING_COMPONENT_TAB:
              comp_string = "XmSTRING_COMPONENT_TAB";
              break; 
         case XmSTRING_COMPONENT_TAG:
              comp_string = "XmSTRING_COMPONENT_TAG";
              break; 
         case XmSTRING_COMPONENT_TEXT:
              comp_string = "XmSTRING_COMPONENT_TEXT";
              break; 
         case XmSTRING_COMPONENT_WIDECHAR_TEXT:
              comp_string = "XmSTRING_COMPONENT_WIDECHAR_TEXT";
              break; 
       }

     return( comp_string );
}

XmString
BuildOrderedString( Components *comp, int num_comp )
{
   int                   i, j;
   XmString              string, temp, finalString = NULL;
   Components            *current_comp;

     for ( j = 0, current_comp = comp; j < num_comp; j++, current_comp++ )
     {
         switch( current_comp->type ) 
         {
             case XmSTRING_COMPONENT_LAYOUT_PUSH:
               if ( strcmp( (char *)current_comp->value, 
                            "XmLEFT_TO_RIGHT" ) == 0 )
                  string = XmStringComponentCreate( current_comp->type,
                                           sizeof( XmDirection ),
                                           &dir_ltor );
               else if ( strcmp( (char *)current_comp->value, 
                            "XmRIGHT_TO_LEFT" ) == 0 )
                  string = XmStringComponentCreate( current_comp->type,
                                           sizeof( XmDirection ),
                                           &dir_rtol );
               break;

	     case XmSTRING_COMPONENT_DIRECTION:
               if ( strcmp( (char *)current_comp->value, 
                            "XmSTRING_DIRECTION_L_TO_R" ) == 0 )
                  string = XmStringComponentCreate( current_comp->type,
                                           sizeof( XmStringDirection ),
                                           &stringdir_ltor );
               else if ( strcmp( (char *)current_comp->value, 
                            "XmSTRING_DIRECTION_R_TO_L" ) == 0 )
                  string = XmStringComponentCreate( current_comp->type,
                                           sizeof( XmStringDirection ),
                                           &stringdir_rtol );
	       break;

	     case XmSTRING_COMPONENT_RENDITION_BEGIN: 
	     case XmSTRING_COMPONENT_RENDITION_END: 
	     case XmSTRING_COMPONENT_TAG: 
	     case XmSTRING_COMPONENT_LOCALE: 
	     case XmSTRING_COMPONENT_TEXT: 
	     case XmSTRING_COMPONENT_LOCALE_TEXT: 
	     case XmSTRING_COMPONENT_WIDECHAR_TEXT: 
                  string = XmStringComponentCreate( current_comp->type, 
                                           strlen( (char *)current_comp->value ), 
                                           current_comp->value ); 
               break;


	     case XmSTRING_COMPONENT_TAB:
	     case XmSTRING_COMPONENT_LAYOUT_POP:
             case XmSTRING_COMPONENT_SEPARATOR:
             case XmSTRING_COMPONENT_END:
                  string = XmStringComponentCreate( current_comp->type, 
                                           current_comp->length, 
                                           current_comp->value ); 
               break;
        }

        temp = finalString; 
        finalString = XmStringConcatAndFree( temp, string );

     }

  return( finalString );
}
   
Boolean
CheckCanonicalOrder( XmStringComponentType *compList )
{
        int                     i, j, previous_comp;
        int                     numPush, numTag, numLocale, numDir,
                                numText, numSeparator, numEnd, numSegments;
        Boolean                 status = True;
        Boolean                 new_segment;
        

        numPush = 0;
        numTag = 0;
        numLocale = 0; 
        numDir = 0;
        numText = 0;
        numSeparator = 0; 
        numEnd = 0;

        i = 0;
        previous_comp = 0;
        while ( compList[i] != NULL )
        {
           for ( j = 0; j < NUM_CANONICAL_COMPONENTS; j++ )
           { 
               if ( compList[i] == canonical_order[j] )
               {
                  switch( compList[i] )
                  { 
                    case XmSTRING_COMPONENT_LAYOUT_PUSH:
                    case XmSTRING_COMPONENT_TAG:
                    case XmSTRING_COMPONENT_LOCALE:
                    case XmSTRING_COMPONENT_DIRECTION:
                    case XmSTRING_COMPONENT_TEXT:
                    case XmSTRING_COMPONENT_LOCALE_TEXT:
                    case XmSTRING_COMPONENT_WIDECHAR_TEXT:
                    case XmSTRING_COMPONENT_LAYOUT_POP:
                    case XmSTRING_COMPONENT_SEPARATOR:
                    case XmSTRING_COMPONENT_END:
                       if ( j <= previous_comp )
                          status = False;
                      break;

                    case XmSTRING_COMPONENT_RENDITION_BEGIN:
                    case XmSTRING_COMPONENT_TAB:
                    case XmSTRING_COMPONENT_RENDITION_END:
                       if ( j < previous_comp )
                          status = False;
                      break;
                  }
               }
           }
           previous_comp = j;
           i++;
        }

    return( status );
}
 
int
GetStringSegmentsByComp( XmString string, int num_comps, 
                   XmStringComponentType ***compTable )
{
	XmStringContext         context;
	XmStringComponentType	compType;
        unsigned int            length;
        XtPointer               value = NULL;
        int                     i, j, k, numSegments, numComps, maxComps;
        int                     numPush, numTag, numLocale, numDir,
                                numText, numSeparator, numEnd;
	Boolean                 new_segment;
        XmString                newString, temp, finalString;

        numPush = 0;
        numTag = 0;
        numLocale = 0; 
        numDir = 0;
        numText = 0;
        numSeparator = 0; 
        numEnd = 0;
        numSegments = 0;
        maxComps = 0;
        numComps = 0;

       /*
        *  Determine how many segments are in the XmString.
        *  Determine the largest number of components in a given
        *  segment.
        */
	XmStringInitContext( &context, string );
	compType = XmStringGetNextTriple( context, &length, &value );  

        new_segment = False;
        for ( i = 0; i < num_comps; i++ ) 
        {
           switch( compType )
           {
             case XmSTRING_COMPONENT_LAYOUT_PUSH:
               numPush++;
               if ( numPush > 0 ) 
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_TAG:
               numTag++;
               if ( numTag > 1 ) 
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_LOCALE:
               numLocale++;
               if ( numLocale > 1 )
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_DIRECTION:
               numDir++;
               if ( numDir > 1 )
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_TEXT:
             case XmSTRING_COMPONENT_LOCALE_TEXT:
             case XmSTRING_COMPONENT_WIDECHAR_TEXT:
               numText++;
               if ( numText > 1 )
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_SEPARATOR:
               numSeparator++; 
               if ( numSeparator > 1 ) 
                  new_segment = True;
               break; 
             case XmSTRING_COMPONENT_END: 
               numEnd++; 
               if ( numEnd > 1 ) 
                  new_segment = True;
               break; 
           } 
      
         if ( value ) XtFree( value ); 
         value = NULL; 

         if ( new_segment )
         {
            numSegments++;
            if ( numComps > maxComps )
                 maxComps = numComps;
            numComps = 0;
         }
         new_segment = False;
         numComps++;
            
         compType = XmStringGetNextTriple( context, &length, &value );  
        } 
        if ( value ) XtFree( value );

        XmStringFreeContext( context );

        *compTable = (XmStringComponentType **)XtMalloc( numSegments *
                       sizeof( XmStringComponentType * ));
        for ( i = 0; i < numSegments; i++ )
            (*compTable)[i] = (XmStringComponentType *)XtMalloc( maxComps + 1 *
                       sizeof( XmStringComponentType ));

        /*
         *  Initialize the list of XmStringComponentTypes.
         */
        for ( i = 0; i < numSegments; i++ )
          for ( j = 0; j < maxComps + 1; j++ )
             (*compTable)[i][j] = NULL;

        numPush = 0;
        numTag = 0;
        numLocale = 0; 
        numDir = 0;
        numText = 0;
        numSeparator = 0; 
        numEnd = 0;

        finalString = NULL;

	XmStringInitContext( &context, string );
	compType = XmStringGetNextTriple( context, &length, &value );  

        j = -1;
        k = 0;
        new_segment = False;
        value = NULL;
        for ( i = 0; i < num_comps; i++ ) 
        {
           switch( compType )
           {
             case XmSTRING_COMPONENT_LAYOUT_PUSH:
               numPush++;
               if ( numPush > 0 )
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_TAG:
               numTag++;
               if ( numTag > 1 )
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_LOCALE:
               numLocale++;
               if ( numLocale > 1 )
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_DIRECTION:
               numDir++;
               if ( numDir > 1 )
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_TEXT:
             case XmSTRING_COMPONENT_LOCALE_TEXT:
             case XmSTRING_COMPONENT_WIDECHAR_TEXT:
               numText++;
               if ( numText > 1 )
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_SEPARATOR:
               numSeparator++;
               if ( numSeparator > 1 )
                  new_segment = True;
               break;

             case XmSTRING_COMPONENT_END:
               numEnd++;
               if ( numEnd > 1 )
                  new_segment = True;
               break;
           }

           if ( new_segment )
           {
             /*  Increment segment index. */
              j++; 

             /*
              * Terminate the list of XmStringComponentTypes from  
              * the previous segment. 
              */
              if ( k > 0 )
                 (*compTable)[j][k+1] = NULL;

              k = 0;
              (*compTable)[j][k] = compType;

              new_segment = False;
           }

           /*
            *  Add the latest component to the component list. 
            */
            else
              (*compTable)[j][k] = compType;

            if ( value ) XtFree( value );
            compType = XmStringGetNextTriple( context, &length, &value );  

          /*  Increment component index. */
           k++;
        }

        if ( value ) XtFree( value );
        XmStringFreeContext( context );

     return( numSegments );
}

/**
void
#ifdef _NO_PROTO
PrintComponentTypes( compList )
	XmStringComponentType	*compList;
#else 
PrintComponentTypes( XmStringComponentType *compList )
#endif
{
   int	                 i;

   i = 0;
   while ( compList[i] != NULL )
       printf("%s\n", CvtCompTypeToString( compList[i++] ));

   return;
}
**/


void
PrintComponentTypes( XmString string )
{
	XmStringContext	context;
	XmStringComponentType	compType;
        unsigned int            length;
        XtPointer               value = NULL;

	XmStringInitContext( &context, string );

        do
        {
	    compType = XmStringGetNextTriple( context, &length, &value );  
            printf("%s - ", CvtCompTypeToString( compType ));
            switch( compType )
            {
               case XmSTRING_COMPONENT_LAYOUT_PUSH:
                 if ( XmDirectionMatch(*(XmDirection *)value, XmLEFT_TO_RIGHT ))
                      printf("XmLEFT_TO_RIGHT");
                 else if ( XmDirectionMatch( *(XmDirection *)value, 
                           XmRIGHT_TO_LEFT ))
                      printf("XmRIGHT_TO_LEFT");
                 printf("\n");
                 break;

               case XmSTRING_COMPONENT_RENDITION_BEGIN:
               case XmSTRING_COMPONENT_RENDITION_END:
               case XmSTRING_COMPONENT_TAG:
               case XmSTRING_COMPONENT_LOCALE:
               case XmSTRING_COMPONENT_TEXT:
               case XmSTRING_COMPONENT_LOCALE_TEXT:
               case XmSTRING_COMPONENT_WIDECHAR_TEXT:
                 printf("%s", (char *)value );
                 printf("\n");
                 break;

               case XmSTRING_COMPONENT_DIRECTION:
                 if ( *(XmStringDirection *)value == XmSTRING_DIRECTION_L_TO_R )
                      printf("XmSTRING_DIRECTION_L_TO_R");
	         else if ( *(XmStringDirection *)value ==
                           XmSTRING_DIRECTION_R_TO_L )
                      printf("XmSTRING_DIRECTION_R_TO_L");
                 printf("\n");
                 break;

               case XmSTRING_COMPONENT_TAB:
               case XmSTRING_COMPONENT_LAYOUT_POP:
               case XmSTRING_COMPONENT_SEPARATOR:
               case XmSTRING_COMPONENT_END:
                 printf("\n");
                 break;
           }

           if ( value ) XtFree( (char *)value );
           value = NULL;
         }
         while ( compType != XmSTRING_COMPONENT_END );

         printf("\n\n");

	 XmStringFreeContext( context );

    return;
}
               
           

      
void
main( int argc, char **argv )
{
   int  		 i, j, k, n;
   Arg                   args[25];
   XmString              stringComp, stringSeg, temp, majorString;
   Components            *comp;
   Segments              *segment;
   XmStringContext	 context;
   XmStringComponentType type;
   XmTextType            text_type;
   unsigned int          length;
   XtPointer             value = (XtPointer)0;
   Boolean               passed, one_dir = False, separator, pop_after;
   char                  *text, *comp_string, buffer[20];
   XmStringTag	         tag, *rendition_tags;
   unsigned int          tag_count;
   XmStringDirection     direction;
   XmDirection           push_before;
   XmStringComponentType unknown_tag = 0;
   unsigned short        unknown_length = 0;
   unsigned char         *unknown_value = (unsigned char *)0, tabs;
   XmRendition           rendition;
   XmTab                 tab;
   XmTabList             tabList;
   Boolean		 status;
   int                   numSegments;
   XmStringComponentType **compTable;         

   CommonTestInit( argc, argv );

  /*
   *  Build an XmString from the components defined in Components structure.
   */
   for ( i = 0; i < NUM_COMPONENTS; i++ )
   {
        comp = &components[i]; 

       /*
        *  Compute the length and value of the components where necessary.
        */
        switch( comp->type )
        {
           case XmSTRING_COMPONENT_TEXT:
           case XmSTRING_COMPONENT_RENDITION_BEGIN:
           case XmSTRING_COMPONENT_RENDITION_END:
             comp->length = ( comp->value ) ? strlen( comp->value ) : 0;
              break;
           case XmSTRING_COMPONENT_DIRECTION:
             comp->length = sizeof( XmStringDirection );
             comp->value = ( one_dir ) ? (XtPointer)&stringdir_rtol : 
                           (XtPointer)&stringdir_ltor;
             one_dir = True;
              break;
        }

        if ( i == 0 )
           majorString =
    	   XmStringComponentCreate( comp->type, comp->length, comp->value );
        else
        {
           stringComp =
    	   XmStringComponentCreate( comp->type, comp->length, comp->value );
           temp = majorString;
           majorString = XmStringConcat( temp, stringComp ); 
           XmStringFree( temp );
           XmStringFree( stringComp );
        }
   }

  /*
   *  Retrieve each of the components in the XmString by
   *  calling XmStringPeekNextTriple() and XmStringGetNextTriple(). 
   */
   XmStringInitContext( &context, majorString ); 
   for ( i = 0; i < NUM_COMPONENTS; i++ )
   {
        comp = &components[i]; 
        comp_string = CvtCompTypeToString( comp->type );
        printf("Component #%d, Component Type = %s\n", i+1, comp_string );
	type = XmStringPeekNextTriple( context );	
        printf("XmStringPeekNextTriple() - "); 
        if ( type == comp->type )
           printf("PASSED.");
        else
           printf("FAILED.");
           printf("\n");

        passed = True;

	type = XmStringGetNextTriple( context, &length, &value );
        printf("XmStringGetNextTriple() - "); 
        if ( type == comp->type ) 
           if ( length == comp->length )
           {
              switch( type )
              {
                case XmSTRING_COMPONENT_TEXT:
                case XmSTRING_COMPONENT_RENDITION_BEGIN:
                case XmSTRING_COMPONENT_RENDITION_END:
                  if (( value &&
                       ( strcmp( (char *)value, (char *)comp->value ) != 0 )) ||
                       ( !value && comp->value )) 
                       passed = False;
                  break;
                case XmSTRING_COMPONENT_SEPARATOR:
                case XmSTRING_COMPONENT_TAB:
                case XmSTRING_COMPONENT_END:
                  if ( value != comp->value )
                     passed = False;
                  break;
                case XmSTRING_COMPONENT_DIRECTION:
                  if (( value && ( *((XmStringDirection *)value) != 
                        *((XmStringDirection *)comp->value ))) ||
                        ( !value && comp->value )) 
                     passed = False;
                  break;
               }
	       if ( value )
	       {
	          XtFree((char *)value);
	          value = (XtPointer)0;
               }
             }
             else
                passed = False;
           else
                passed = False;

           if ( passed )
              printf("PASSED.");
           else
              printf("FAILED.");

           printf("\n\n");
   }
    XmStringFreeContext( context ); 
    printf("\n\n\n");

   CommonPause();

  /*
   *  Reinitialize context -- and retrieve the contents of the string
   *  again, this time calling XmStringPeekNextComponent() and
   *  XmStringGetNextComponent().
   */
   XmStringInitContext( &context, majorString ); 
   for ( i = 0; i < NUM_COMPONENTS; i++ )
   {
        comp = &components[i]; 
        comp_string = CvtCompTypeToString( comp->type );
        printf("Component #%d, Component Type = %s\n", i+1, comp_string );

        passed = True;
        type = XmStringPeekNextComponent( context );
        printf("XmStringPeekNextComponent() - ");
        if ( type != comp->type )
           passed = False;

        if ( passed )
           printf("PASSED. \n");
        else
           printf("FAILED. \n");

        passed = True;

        type = XmStringGetNextComponent( context, &text, &tag, &direction,
                 &unknown_tag, &unknown_length, &unknown_value );
        printf("XmStringGetNextComponent() - ");
        if ( type == comp->type || type == XmSTRING_COMPONENT_UNKNOWN )
           switch( type )
           {
             case XmSTRING_COMPONENT_TEXT:
                if (( text &&
                    ( strcmp( text, (char *)comp->value ) != 0 )) ||
                    ( !text && comp->value ))
                    passed = False;
                if ( text ) XtFree( text );
                break;
             case XmSTRING_COMPONENT_DIRECTION:
               if ( direction != *((XmStringDirection *)comp->value )) 
                  passed = False;
               break;
             case XmSTRING_COMPONENT_SEPARATOR:
             case XmSTRING_COMPONENT_END:
                break;
             case XmSTRING_COMPONENT_UNKNOWN:
                switch( unknown_tag )
                { 
                  case XmSTRING_COMPONENT_RENDITION_BEGIN:
                  case XmSTRING_COMPONENT_RENDITION_END:
                    if ( unknown_value && 
                       ( strcmp( (char *)unknown_value, 
                       (char *)comp->value ) != 0 ) ||
                       ( !unknown_value && comp->value ))
                      passed = False;
                    if ( passed &&
                         unknown_length != comp->length )
                      passed = False;
                    break;                         
                  case XmSTRING_COMPONENT_TAB:
                    if ( (XtPointer)unknown_value != comp->value )
                      passed = False;
                    if ( passed &&
                         unknown_length != comp->length )
                      passed = False;
                    break;
                }
                break;
            }
           else
            passed = False;

           if ( passed )
              printf("PASSED.");
           else
              printf("FAILED.");
           printf("\n\n");

           unknown_tag = 0;
           unknown_length = 0;
           if ( unknown_value )
           {
              XtFree((char *)unknown_value);
              unknown_value = (unsigned char *)0;
           }
      }

    XmStringFreeContext( context ); 
    XmStringFree( majorString );

   CommonPause();

    printf("\n\n");


   /*
    *  Build XmString from segments defined in Segments structure. 
    */
    j = 0;
    for ( i = 0; i < NUM_SEGMENTS; i++ )
    {
       segment = &segments[i];
       if ( i == 0 )
         majorString = XmStringSegmentCreate( segment->text, segment->tag,
                     segment->direction, segment->separator );      
       else if ( i > 0 )
       {
         stringSeg = XmStringSegmentCreate( segment->text, segment->tag,
                     segment->direction, segment->separator );      
         temp = majorString;
         majorString = XmStringConcat( temp, stringSeg );
         XmStringFree( temp );
         XmStringFree( stringSeg );
       }
     }

    /*
     *  Retrieve segments from the XmString using XmStringGetNextSegment(). 
     */
    text = (char *)0;
    tag = (XmStringTag)0;
    XmStringInitContext( &context, majorString ); 
    for ( i = 0; i < NUM_SEGMENTS; i++ )
    {
       segment = &segments[i];
       printf("Segment #%d\n", i+1 );
       printf("XmStringGetNextSegment() - ");
       if ( XmStringGetNextSegment( context, &text, &tag, 
              &direction, &separator )) 
       {
         passed = True;
         if (( text && ( strcmp( text, segment->text )) != 0 ) ||
             ( !text && text != segment->text )) 
             passed = False;

         if ( passed && ( tag && ( strcmp( tag, segment->tag ) != 0 )) ||
             ( !tag && tag != segment->tag ))
             passed = False;

         if ( passed && direction != segment->direction )
             passed = False;

         if ( passed && separator != segment->separator )
             passed = False;
       }
       else
         passed = False;
    
       if ( text ) {
          XtFree((char *) text );
          text = (char *)0;
       }
       if ( tag ) {
          XtFree((char *) tag );
          tag = (XmStringTag)0;
       }
       if ( passed )
          printf("PASSED. \n");
       else
          printf("FAILED. \n");

     }
     printf("\n");
     XmStringFreeContext( context );
     XmStringFree( majorString );

    CommonPause();

    n = 0;
    XtSetArg( args[n], XmNwidth, DISPLAY_WIDTH ); n++;
    XtSetArg( args[n], XmNheight, DISPLAY_HEIGHT ); n++;
    XtSetArg( args[n], XmNmarginWidth, 0 ); n++;
    XtSetArg( args[n], XmNmarginHeight, 0 ); n++;
    bboard = XmCreateBulletinBoard( Shell1, "bulletinBoard", args, n );
    XtManageChild( bboard );

  /*  Create Drawing Area. */
    n = 0;
    XtSetArg( args[n], XmNx, 0 ); n++;
    XtSetArg( args[n], XmNy, 0 ); n++;
    XtSetArg( args[n], XmNwidth, DISPLAY_WIDTH ); n++;
    XtSetArg( args[n], XmNheight, DISPLAY_HEIGHT ); n++;
    XtSetArg( args[n], XmNbackground, CommonGetColor("light blue")); n++;
    drawingArea = XmCreateDrawingArea( bboard, "DrawArea", args, n );
    XtManageChild( drawingArea );

    XtAddCallback( drawingArea, XmNexposeCallback, DrawString, NULL );

    n = 0;
    XtSetArg(args[n], XmNforeground, &gcv.foreground); n++;
    XtSetArg(args[n], XmNbackground, &gcv.background); n++;
    XtGetValues(drawingArea, args, n);

    fontStruct = (XFontStruct *)XLoadQueryFont( display, "fixed" );

   /*
    *  Create tabList.
    */
    tab = XmTabCreate( 1.0, XmINCHES, XmABSOLUTE, XmALIGNMENT_BEGINNING,
                       (char *)0 );

    tabList = XmTabListInsertTabs( NULL, &tab, 1, 0 );

    XmTabFree( tab );

   /*
    *  Set up renderTable for displaying strings created using
    *  components in ordered_comp[] array.
    */
    n = 0;
    XtSetArg( args[n], XmNfont, (XtPointer)fontStruct ); n++;
    XtSetArg( args[n], XmNfontType, XmFONT_IS_FONT ); n++;
    XtSetArg( args[n], XmNtabList, tabList ); n++;
    XtSetArg( args[n], XmNrenditionForeground, CommonGetColor("black")); n++;
    rendition = XmRenditionCreate( drawingArea, "render_tag1", args, n );

    renderTable = XmRenderTableAddRenditions( NULL, &rendition, 1, XmMERGE_REPLACE );

    XmRenditionFree( rendition );

    n = 0;
    XtSetArg( args[n], XmNfontName, "9x15" ); n++;
    XtSetArg( args[n], XmNfontType, XmFONT_IS_FONT ); n++;
    XtSetArg( args[n], XmNrenditionForeground, CommonGetColor("red")); n++;
    rendition = XmRenditionCreate( drawingArea, "render_tag2", args, n );

    renderTable = XmRenderTableAddRenditions( renderTable, &rendition, 1, XmMERGE_REPLACE );
    
    XmRenditionFree( rendition );
    XmTabListFree( tabList );

    XtRealizeWidget( Shell1 );

    gcv.font = fontStruct->fid;
    gc = XCreateGC( display, XtWindow( drawingArea ),
                    GCForeground | GCBackground | GCFont, &gcv );


    for ( i = 0; i < NUM_ORDERED_STRINGS; i++ )
    {
      majorString =
        BuildOrderedString( &ordered_comp[i][0], NUM_ORDERED_COMPONENTS );
      draw_string = XmStringCopy( majorString );
      XClearArea(XtDisplay(drawingArea), XtWindow(drawingArea), 
                 0, 0, 0, 0, TRUE);
      XmStringFree( draw_string );
      PrintComponentTypes( majorString ); 
/**
      numSegments = GetStringSegmentsByComp( majorString, NUM_ORDERED_COMPONENTS,
                    &compTable ); 
      printf("XmString contains %d segments\n", numSegments );
      for ( j = 0; j < numSegments; j++ )
      {
         status = CheckCanonicalOrder( compTable[j] );
         printf("Checking canonical order of segment #%d:\n", j+1 );
         if ( status )
            printf("XmString components were returned in the CORRECT order.");
         else
            printf("XmString components were returned in the INCORRECT order.");
         printf("\n\n");
         PrintComponentTypes( compTable[j] );
         	printf("\n\n");
      }
**/
      CommonPause();
    }

    CommonPause();

    XtAppMainLoop( app_context );
}
