/*
 * This file contains routines to draw and update the screen.
 *
 * Copyright 1990 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 *
 * Tom Coppeto
 * MIT Network Group
 * 8 August 1990
 *
 *    $Source: /afs/net.mit.edu/tools/src/xport/RCS/xstuff.c,v $
 *    $Author: tom $
 *    $Locker: tom $
 *
 */

#ifndef lint
static char *rcsid = "$Header: /afs/net.mit.edu/tools/src/xport/RCS/xstuff.c,v 1.2 90/08/19 16:19:18 tom Exp Locker: tom $";
#endif

#include <X11/IntrinsicP.h>
#include <X11/CompositeP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/cursorfont.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/StripChart.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/Sme.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/Repeater.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/ScrollbarP.h>
#include <X11/Xaw/Viewport.h>

#include <X11/Xtw/Rolo.h>
#include <X11/Xtw/Digit.h>
#include <X11/Xtw/Chooser.h>
#include <X11/Xtw/Frame.h>

#include <rope.h>
#include "xrmonwatch.h"

extern XtAppContext app_con;
extern Widget toplevel;
static Widget IPpopup = (Widget) NULL;
static Widget ATpopup = (Widget) NULL;
static Widget FLpopup = (Widget) NULL;

static void create_row();
static void create_commands();
static Widget create_box();
static Widget create_form();


static void cb_filterCreate();
static void cb_filterApply();
static void cb_sensitize();

static void make_chooser_list_with_string_indices();

static Widget digitInputs[10];
static int ndi = 1;

char **filter  = (char **) NULL;
char **mask    = (char **) NULL;
char **notmask = (char **) NULL;
int filter_length = 0;
int filter_offset = -1;

#define SLICE 400

static int num_filters = 1;

filter_ip_panel(w)
{
  Widget box;
  Widget form;
  Widget rolo;

  if(IPpopup)
    {
      XtMapWidget(IPpopup);
      XRaiseWindow(XtDisplay(IPpopup), XtWindow(IPpopup));
      return;
    }

  IPpopup = XtCreatePopupShell("fltPopup", 
			       topLevelShellWidgetClass, 
			       toplevel, NULL, 0);
  form = XtCreateManagedWidget("TCPIPFrame", frameWidgetClass, IPpopup, 
			       NULL, 0);
  rolo = create_form(form);

  /*
   * Ethernet box
   */

  box = create_box(rolo,  &parts[R_Ethernet]);
  create_row(box, &parts[R_EthernetV2],          &parts[R_Ethernet8023]);
  create_row(box, &parts[R_EthernetBroadcast],   &parts[R_EthernetMulticast]);
  create_row(box, &parts[R_EthernetLength],      NULL);
  create_row(box, &parts[R_EthernetSrcAddress],  NULL);
  create_row(box, &parts[R_EthernetDstAddress],  NULL);
  create_row(box, &parts[R_EthernetSrcVendor],   NULL);
  create_row(box, &parts[R_EthernetDstVendor],   NULL);

  XtAddCallback(parts[R_EthernetBroadcast].widget, XtNcallback, cb_sensitize,
		R_EthernetBroadcast);		
  XtAddCallback(parts[R_EthernetMulticast].widget, XtNcallback, cb_sensitize,
		R_EthernetMulticast);

  /*
   * 802.2
   */

  box = create_box(rolo,  &parts[R_LLC]);
  create_row(box, &parts[R_LLCType],             &parts[R_LLCClass]);
  create_row(box, &parts[R_LLCFormat],           &parts[R_LLCCommand]);
  create_row(box, &parts[R_LLCSrcAddress],       &parts[R_LLCDstAddress]);
  create_row(box, &parts[R_LLCSrcAddrDesig],     &parts[R_LLCDstAddrDesig]);
  create_row(box, &parts[R_LLCSendSequence],     &parts[R_LLCRecvSequence]);
  create_row(box, &parts[R_LLCPFBit],            &parts[R_LLCCRIdentifier]);
  create_row(box, &parts[R_LLCSupervisoryBit],   &parts[R_LLCInformation]);

  /*
   * SNAP
   */

  box = create_box(rolo,  &parts[R_SNAP]);
  create_row(box, &parts[R_SNAPAddress],         &parts[R_SNAPNull]);

  /*
   * ARP
   */

  box = create_box(rolo,  &parts[R_ARP]);
  create_row(box, &parts[R_ARPSrcPhysicalAddress],    NULL);
  create_row(box, &parts[R_ARPTargetPhysicalAddress], NULL);
  create_row(box, &parts[R_ARPSrcVendor],             NULL);
  create_row(box, &parts[R_ARPTargetVendor],          NULL);
  create_row(box, &parts[R_ARPSrcProtocolAddress],    NULL);
  create_row(box, &parts[R_ARPTargetProtocolAddress], NULL);
  create_row(box, &parts[R_ARPSrcName],               NULL);
  create_row(box, &parts[R_ARPTargetName],            NULL);


  /*
   * IP
   */

  box = create_box(rolo,  &parts[R_IP]);
  create_row(box, &parts[R_IPVersion],           &parts[R_IPHeaderLength]);
  create_row(box, &parts[R_IPType],              &parts[R_IPLength]);
  create_row(box, &parts[R_IPFlags],	         &parts[R_IPFragmentOffset]);
  create_row(box, &parts[R_IPIdentification],    &parts[R_IPTTL]);
  create_row(box, &parts[R_IPProtocol],	         &parts[R_IPChecksum]);
  create_row(box, &parts[R_IPSrcAddress],        &parts[R_IPDstAddress]);
  create_row(box, &parts[R_IPSrcName],           &parts[R_IPDstName]);


  /*
   *  ICMP
   */
  
  box = create_box(rolo,  &parts[R_ICMP]);
  create_row(box, &parts[R_ICMPType],	         &parts[R_ICMPCode]);
  create_row(box, &parts[R_ICMPChecksum],	 &parts[R_ICMPIPHeader]);
  create_row(box, &parts[R_ICMPPointer],         &parts[R_ICMPGateway]);
  create_row(box, &parts[R_ICMPIdentifier],	 &parts[R_ICMPSequence]);
  create_row(box, &parts[R_ICMPOriginateTimestamp],
	     &parts[R_ICMPReceiveTimestamp]);
  create_row(box, &parts[R_ICMPTransmitTimestamp], &parts[R_ICMPData]);

  /*
   *  UDP
   */

  box = create_box(rolo,  &parts[R_UDP]);
  create_row(box, &parts[R_UDPChecksum],         &parts[R_UDPLength]);
  create_row(box, &parts[R_UDPSrcPort],          &parts[R_UDPDstPort]);
  create_row(box, &parts[R_UDPSrcPortName],      &parts[R_UDPDstPortName]);
                        

  /*
   *  Zephyr
   */

#ifdef ZEPHYR
  box = create_box(rolo,  &parts[R_Zephyr]);
  create_row(box, &parts[R_ZPacket],             &parts[R_ZVersion]);
  create_row(box, &parts[R_ZKind],               &parts[R_ZNull]);
  create_row(box, &parts[R_ZSender],             &parts[R_ZRecipient]);
  create_row(box, &parts[R_ZClass],              &parts[R_ZInstance]);
  create_row(box, &parts[R_ZOpcode],             &parts[R_ZNull]);
#endif /* ZEPHYR */
  
  /*
   *  TCP
   */

  box = create_box(rolo,  &parts[R_TCP]);
  create_row(box, &parts[R_TCPChecksum],	 &parts[R_TCPAck]);
  create_row(box, &parts[R_TCPSequence],	 &parts[R_TCPWindow]);
  create_row(box, &parts[R_TCPOffset],	         &parts[R_TCPUrgent]);
  create_row(box, &parts[R_TCPSrcPort],          &parts[R_TCPDstPort]);
  create_row(box, &parts[R_TCPSrcPortName],      &parts[R_TCPDstPortName]);
  create_row(box, &parts[R_TCPFlags],	         &parts[R_TCPNull]);

  create_commands(form, IPpopup);
  XtPopup(IPpopup, XtGrabNone);
  return;
}



filter_at_panel(w)
{
  Widget form;
  Widget box;

  if(ATpopup)
    {
      XtMapWidget(ATpopup);
      XRaiseWindow(XtDisplay(ATpopup), XtWindow(ATpopup));
      return;
    }

  ATpopup = XtCreatePopupShell("ATPopup", 
			       topLevelShellWidgetClass, 
			       toplevel, NULL, 0);
  
  form = create_form(ATpopup);


  /*
   * Ethernet box
   */

  box = create_box(form,  &parts[R_Ethernet]);
  create_row(box, &parts[R_EthernetType],        &parts[R_EthernetLength]);
  create_row(box, &parts[R_EthernetSrcAddress],  &parts[R_EthernetDstAddress]);
  create_row(box, &parts[R_EthernetSrcVendor],   &parts[R_EthernetDstVendor]);
  create_row(box, &parts[R_EthernetVersion],     &parts[R_EthernetMulticast]);

  /*
   * 802.2
   */

  box = create_box(form,  &parts[R_LLC]);
  create_row(box, &parts[R_LLCType],             &parts[R_LLCClass]);
  create_row(box, &parts[R_LLCFormat],           &parts[R_LLCCommand]);
  create_row(box, &parts[R_LLCSrcAddress],       &parts[R_LLCDstAddress]);
  create_row(box, &parts[R_LLCSrcAddrDesig],     &parts[R_LLCDstAddrDesig]);
  create_row(box, &parts[R_LLCSendSequence],     &parts[R_LLCRecvSequence]);
  create_row(box, &parts[R_LLCPFBit],            &parts[R_LLCCRIdentifier]);
  create_row(box, &parts[R_LLCSupervisoryBit],   &parts[R_LLCInformation]);


  /*
   * SNAP
   */

  box = create_box(form,  &parts[R_SNAP]);
  create_row(box, &parts[R_SNAPAddress],         &parts[R_SNAPNull]);

  
  /*
   * AARP
   */

  box = create_box(form,  &parts[R_AARP]);
  create_row(box, &parts[R_AARPType],            &parts[R_AARPNull]);
  create_row(box, &parts[R_AARPHardwareType],	 &parts[R_AARPProtocolType]);
  create_row(box, &parts[R_AARPHardwareLength],  &parts[R_AARPProtocolLength]);
  create_row(box, &parts[R_AARPSrcHardwareAddress], 
	     &parts[R_AARPDstHardwareAddress]);
  create_row(box, &parts[R_AARPSrcProtocolAddress], 
	     &parts[R_AARPDstProtocolAddress]);



  /*
   * DDP
   */

  box = create_box(form,  &parts[R_DDP]);
  create_row(box, &parts[R_DDPLength],	         &parts[R_DDPHopCount]);
  create_row(box, &parts[R_DDPType],   	         &parts[R_DDPChecksum]);
  create_row(box, &parts[R_DDPSrcNetwork],	 &parts[R_DDPDstNetwork]);
  create_row(box, &parts[R_DDPSrcNode],	         &parts[R_DDPDstNode]);
  create_row(box, &parts[R_DDPSrcSocket],	 &parts[R_DDPDstSocket]);
  create_row(box, &parts[R_DDPSrcName],	         &parts[R_DDPDstName]);
  create_row(box, &parts[R_DDPSrcType],	         &parts[R_DDPDstType]);
  create_row(box, &parts[R_DDPSrcZone],	         &parts[R_DDPDstZone]);


  /*
   *  RTMP
   */

  box = create_box(form,  &parts[R_RTMP]);
  create_row(box, &parts[R_RTMPVersion],         &parts[R_RTMPFunction]);
  create_row(box, &parts[R_RTMPSrcNetwork],      &parts[R_RTMPSrcNode]);
  create_row(box, &parts[R_RTMPRangeStart],      &parts[R_RTMPRangeEnd]);
  create_row(box, &parts[R_RTMPDistance],        &parts[R_RTMPHops]);
  create_row(box, &parts[R_RTMPSrcNodeLength],   &parts[R_RTMPNetwork]);

  /*
   *  AEP
   */

  box = create_box(form,  &parts[R_AEP]);
  create_row(box, &parts[R_AEPType],	         &parts[R_AEPNull]);


  /*
   *  NBP
   */

  box = create_box(form,  &parts[R_NBP]);
  create_row(box, &parts[R_NBPType],	         &parts[R_NBPIdentification]);
  create_row(box, &parts[R_NBPTupleCount],       &parts[R_NBPNetwork]);
  create_row(box, &parts[R_NBPNode],             &parts[R_NBPSocket]);
  create_row(box, &parts[R_NBPObjectLength],     &parts[R_NBPObjectEntity]);
  create_row(box, &parts[R_NBPTypeLength],       &parts[R_NBPTypeEntity]);
  create_row(box, &parts[R_NBPZoneLength],       &parts[R_NBPZoneEntity]);
  create_row(box, &parts[R_NBPEnumerator],       &parts[R_NBPNull]);

  /*
   * ZIP
   */

  box = create_box(form,  &parts[R_ZIP]);
  create_row(box, &parts[R_ZIPNetworkCount],     &parts[R_ZIPNetwork]);
  create_row(box, &parts[R_ZIPZoneLength],       &parts[R_ZIPZone]);
  create_row(box, &parts[R_ZIPType],	         &parts[R_ZIPNull]);

  /*
   * ADSP
   */

  box = create_box(form,  &parts[R_ADSP]);
  create_row(box, &parts[R_ADSPConnId],          &parts[R_ADSPControlCode]);
  create_row(box, &parts[R_ADSPFirstSeq],        &parts[R_ADSPNextSeq]);
  create_row(box, &parts[R_ADSPWindow],          &parts[R_ADSPDescriptor]);


  XtPopup(ATpopup, XtGrabNone);
  return;
}





/*
 * for creating widgets
 */

static void
create_row(parent, left, right)
     Widget parent;
     struct PART *left;
     struct PART *right;
{
  Arg carg;
  Widget w;
  Widget t;
  char buf[100];
  int i;

  sprintf(buf, "%sForm",   left->resource.s);
  w = XtCreateManagedWidget(buf, formWidgetClass, parent, NULL, 0);
  sprintf(buf, "%sLabel",  left->resource.s);
  XtSetArg(carg, XtNlabel, left->label.s);
  XtCreateManagedWidget(buf, labelWidgetClass, w, &carg, 1);
  sprintf(buf, "%sValue", left->resource.s);
  
  switch(left->type)
    {
    case R_Boolean:
      XtSetArg(carg, XtNstate, left->state);
      t = XtCreateManagedWidget(buf, toggleWidgetClass, w, &carg, 1);    
      XtAddCallback(t, XtNcallback, cb_chdisplay, &(right->state));
      break;
    case R_String:
    case R_MACAddress:
    case R_IPAddress:
      if(left->table)
	{     
	  t = XtCreateManagedWidget(buf, chooserWidgetClass, w, &carg, 0);
	  make_chooser_list_with_string_indices(t, left->table);
	}
      else
	t = XtCreateManagedWidget(buf, asciiTextWidgetClass, w, &carg, 0);    
      break;
    case R_Integer:
      XtSetArg(carg, XtNlabel, "");
      t = XtCreateManagedWidget(buf, digitWidgetClass, w, &carg, 1);    
      break;
    }
  left->widget = (char *) t;

  if(right)
    {
      sprintf(buf, "%sValue", right->resource.s);
      switch(right->type)
	{
	case R_Boolean:
	  XtSetArg(carg, XtNstate, right->state);
	  t = XtCreateManagedWidget(buf, toggleWidgetClass, w, &carg, 1);    
	  XtAddCallback(t, XtNcallback, cb_chdisplay, &(right->state));
	  break;
	case R_String:
	case R_MACAddress:
	case R_IPAddress:
	  /* XtSetArg(carg, XtNValue, right->value.string); */
	  if(right->table)
	    {
	      t = XtCreateManagedWidget(buf, chooserWidgetClass, w, &carg, 0);
	      make_chooser_list_with_string_indices(t, right->table);
	    }
	  else
	    t = XtCreateManagedWidget(buf, asciiTextWidgetClass, w, &carg, 0);
	  break;
	case R_Integer:
	  XtSetArg(carg, XtNlabel, "");
	  t = XtCreateManagedWidget(buf, digitWidgetClass, w, &carg, 1);    
	  break;
	}
      
      sprintf(buf, "%sLabel",  right->resource.s);
      XtSetArg(carg, XtNlabel, right->label.s);
      XtCreateManagedWidget(buf, labelWidgetClass, w, &carg, 1);
      right->widget = (char *) t;
    }
}


static Widget
create_box(parent, box)
     Widget parent;
     struct PART *box;
{
  Widget w;
  char buf[100];
  Arg args[2];

  XtSetArg(args[0], XtNlabel, box->label.s);
  w = XtCreateManagedWidget("selectForm", formWidgetClass, parent, args, 1);

  sprintf(buf, "%sLabel",  box->resource.s);
  XtSetArg(args[0], XtNlabel, box->label.s);
  XtCreateManagedWidget(buf, labelWidgetClass, w, args, 1);
  return(w);
}


static Widget
create_form(parent)  
     Widget parent;
{
  Widget w;
  Arg arg;

  w = XtCreateManagedWidget("rolo", roloWidgetClass, parent, NULL, 0);
  return(w);
}


static void
create_commands(parent, popup)  
     Widget parent;
     Widget popup;
{
  Widget b;
  Arg args[3];

  b = XtwAddFrameCommand("commandClose", commandWidgetClass, parent, NULL, 0);
  XtAddCallback(b, XtNcallback, cb_close_popup, popup);
  b = XtwAddFrameCommand("commandCreate", commandWidgetClass, parent, NULL, 0);
  XtAddCallback(b, XtNcallback, cb_filterCreate, NULL);
  b = XtwAddFrameCommand("commandApply", commandWidgetClass, parent, NULL, 0);
  XtAddCallback(b, XtNcallback, cb_filterApply, NULL);
  b = XtwAddFrameCommand("commandShow", commandWidgetClass, parent, NULL, 0);
  XtAddCallback(b, XtNcallback, cb_filterList, popup);

  XtSetArg(args[0], XtNmaxValue, (XtArgVal) num_filters);
  XtSetArg(args[1], XtNminValue, (XtArgVal) 1);
  XtSetArg(args[2], XtNvalue,    (XtArgVal) 1);
  b = XtwAddFrameCommand("commandFilter", digitWidgetClass, parent, args, 3);
  digitInputs[ndi-1] = b;
  digitInputs[ndi] = (Widget) NULL;

  b = XtwAddFrameCommand("commandNot", toggleWidgetClass, parent, NULL, 0);
  
  return;
}


static void 
cb_filterCreate(w, data, closure)
     Widget;
     XtPointer data;
     XtPointer closure;
{
  int i = 0;

  ++num_filters;
  filter  = (char **) realloc(filter,  (num_filters+1) * sizeof(char *));
  mask    = (char **) realloc(mask,    (num_filters+1) * sizeof(char *));
  notmask = (char **) realloc(notmask, (num_filters+1) * sizeof(char *));
  filter[num_filters-1]  = (char *) malloc(SLICE*2);
  mask[num_filters-1]    = (char *) malloc(SLICE*2);
  notmask[num_filters-1] = (char *) malloc(SLICE*2);
  bzero(filter[num_filters-1],  SLICE*2);
  bzero(mask[num_filters-1],    SLICE*2);
  bzero(notmask[num_filters-1], SLICE*2);
  filter[num_filters]    = (char *) NULL;
  mask[num_filters]      = (char *) NULL;
  notmask[num_filters]   = (char *) NULL;

  while(i < ndi)
    {
      
      XtwSetRange(digitInputs[i], 1, num_filters);
      XtwSetDigit(digitInputs[i], num_filters);
      ++i;
    }
}



static void
cb_filterApply(w, data, closure)
     Widget w;
     XtPointer data;
     XtPointer closure;
{
  struct FILTER *f;
  char *c;
  int i,n;
  
  filter_offset = 0;
  filter_length = 0;

  if(!filter)
    {
      filter  = (char **) malloc((num_filters+1) * sizeof(char *));
      mask    = (char **) malloc((num_filters+1) * sizeof(char *));
      notmask = (char **) malloc((num_filters+1) * sizeof(char *));
      filter[num_filters-1]  = (char *) malloc(SLICE*2);
      mask[num_filters-1]    = (char *) malloc(SLICE*2);
      notmask[num_filters-1] = (char *) malloc(SLICE*2);
      bzero(filter[num_filters-1],  SLICE*2);
      bzero(mask[num_filters-1],    SLICE*2);
      bzero(notmask[num_filters-1], SLICE*2);
      filter[num_filters]    = (char *) NULL;
      mask[num_filters]      = (char *) NULL;
      notmask[num_filters]   = (char *) NULL;
    }

  
  for(n=0; n < num_filters; n++)
    {
      for(i = 0; i < SLICE*2-1; i++)
	{
	  filter[n][i]  = '0';
	  mask[n][i]    = '0';
	  notmask[n][i] = '0';
	}
    }

  i = 1;
  while(parts[i].resource.s)
    {
      f = parts[i].filter;
      while(f && parts[i].fltproc)
	{
	  f->data    = str_clearString(f->data);
	  f->mask    = str_clearString(f->mask);
	  f->notmask = str_clearString(f->notmask);
	  f = f->next;
	}
      ++i;
    }


  i = 1;
  while(parts[i].resource.s)
    {
      f = parts[i].filter;
      while(f && parts[i].fltproc)
	{
	  (*parts[i].fltproc)(&parts[i], f);
	
	  if(f->data.length)
	    {
	      strncpy(filter[f->index]  + f->offset,
		      f->data.s, f->data.length);
	      strncpy(mask[f->index]    + f->offset,
		      f->mask.s, f->data.length);
	      strncpy(notmask[f->index] + f->offset, 
		      f->notmask.s, f->data.length);

	      if(filter_offset == -1)
		{
		  filter_length = f->data.length;
		  filter_offset = f->offset;
		}
	      else
		if(f->offset < filter_offset)
		  filter_length += filter_offset - f->offset;
		else
		  filter_length += f->offset - (filter_offset + filter_length) 
		    + f->data.length;

	      if(filter_offset > f->offset)
		filter_offset = f->offset;
	    }
	  f = f->next;
	}
       ++i;
    }
  printf("%*.*s\n\n%*.*s\n\n%*.*s\n", 
	 filter_length, filter_length, filter[0]+filter_offset, 
	 filter_length, filter_length, mask[0]+filter_offset, 
	 filter_length, filter_length, notmask[0]+filter_offset);
}


static void
cb_sensitize(w, type, closure)
     Widget w;
     int type;
     XtPointer closure;
{
  Arg arg;
  Boolean state;

  XtSetArg(arg, XtNstate, &state);
  XtGetValues(w, &arg, 1);
  if((type == R_EthernetBroadcast) || (type == R_EthernetMulticast))
    {
      if(state)
	XtSetArg(arg, XtNsensitive, False);
      else
	XtSetArg(arg, XtNsensitive, True);
      XtSetValues(parts[R_EthernetDstAddress].widget, &arg, 1);
    }
}


void
filter_list_panel(w)
{
  Widget box;
  Widget form;
  Widget list;
  Widget b;
  static String s[] = {"foo", "bar"};

  if(FLpopup)
    {
      XtMapWidget(FLpopup);
      XRaiseWindow(XtDisplay(FLpopup), XtWindow(FLpopup));
      return;
    }

  FLpopup = XtCreatePopupShell("flistPopup", 
			       topLevelShellWidgetClass, 
			       toplevel, NULL, 0);
  form = XtCreateManagedWidget("frame", frameWidgetClass, FLpopup, NULL, 0);

  list = XtCreateManagedWidget("List", listWidgetClass, form, NULL, 0);
  XawListChange(list, filter, ndi, 20, 1);
  b = XtwAddFrameCommand("commandClose", commandWidgetClass, form, NULL, 0);
  XtAddCallback(b, XtNcallback, cb_close_popup, FLpopup);

  XtPopup(FLpopup, XtGrabNone);  
}



/*
 * Here's an ugly glue function that translates strings in our table
 * to strings the List widget expects.
 */

static void
make_chooser_list_with_string_indices(w, table)
     Widget w;
     struct TABLE table;
{
  struct ROW *rp;
  char **s2;
  char **s;
  int i;

  if(!table.rows)
    return;
  rp = table.rows;

  i = 0;
  while(rp[i++].name);
  s  = (String *) XtMalloc((i+1) * sizeof(String));
  s2 = (String *) XtMalloc((i+1) * sizeof(String));
  if(!s || !s2)
    return;

  i = 0;
  while(rp[i].name)
    {
      s[i]  = rp[i].name;
      s2[i] = rp[i].svalue;
      ++i;
    }
  s[i]  = (char *) NULL;
  s2[i] = (char *) NULL;
  XtwChooserChange(w, s, s2, i, 0, 1);
  return;
}
