예제 #1
0
파일: flags.c 프로젝트: Akheon23/nvopencc
/* ====================================================================
 *
 * Duplicate_Value
 *
 * Given an option descriptor, duplicate the current value of the
 * associated user variable into the given container.  The container
 * passed must be 64 bits in size.  Pointers are simply replicated
 * (i.e. not their pointees), and are stored in the initial part of the
 * container.  Values smaller than 64 bits are converted to 64 bits for
 * storage in the container.
 *
 * NOTE: this routine is different from Copy_option in that it puts
 * the values in the OPTVAL container and so sign extends.
 * ====================================================================*/
static void
Duplicate_Value ( OPTION_DESC *odesc, OPTVAL *container )
{
  void *var = ODESC_variable(odesc);

  switch ( ODESC_kind(odesc) ) {
    case OVK_NONE:
    case OVK_BOOL:
      container->i = *((BOOL *)var);
      break;
    case OVK_INT32:
      container->i = *((INT32 *)var);
      break;
    case OVK_UINT32:
      container->i = *((UINT32 *)var);
      break;
    case OVK_INT64:
      container->i = *((INT64 *)var);
      break;
    case OVK_UINT64:
      container->i = *((UINT64 *)var);
      break;
    case OVK_NAME:
    case OVK_SELF:
      container->p = *((char **)var);
      break;
    case OVK_LIST:
      container->p = *((OPTION_LIST **)var);
      break;
    default:
      break;
  }
}
예제 #2
0
파일: flags.c 프로젝트: Akheon23/nvopencc
static BOOL
Modified_Option ( OPTION_DESC *odesc )
{
  void *var = ODESC_variable(odesc);
  ODESC_AUX *aux = ODESC_aux(odesc);
  UINT64 cur;

  switch ( ODESC_kind(odesc) ) {
    case OVK_NONE:
    case OVK_BOOL:
      cur = (UINT64)*((BOOL*)var);
      break;
    case OVK_INT32:
      cur = (UINT64)*((INT32*)var);
      break;
    case OVK_UINT32:
      cur = (UINT64)*((UINT32*)var);
      break;
    case OVK_INT64:
      cur = (UINT64)*((INT64*)var);
      break;
    case OVK_UINT64:
      cur = (UINT64)*((UINT64*)var);
      break;
    case OVK_NAME:
    case OVK_SELF:
    case OVK_LIST:
      return ( *((void**)var) != ODA_last_p(aux) );
    default:
      break;
  }

  /* For the scalar cases, still need to check: */
  return ( cur != ODA_last_i(aux) );
}
예제 #3
0
파일: flags.c 프로젝트: Akheon23/nvopencc
static void
Update_Scalar_Value ( OPTION_DESC *odesc, UINT64 val )
{
  void *var = ODESC_variable(odesc);
  ODESC_AUX *aux = ODESC_aux(odesc);

  if ( val != ODA_last_i(aux) ) {
    Set_ODA_mod(aux);
    ODA_last_i(aux) = val;
  }
  Set_ODA_set(aux);

  switch ( ODESC_kind(odesc) ) {
    case OVK_NONE:
    case OVK_BOOL:
      *((BOOL *)var) = (BOOL)val;
      break;
    case OVK_INT32:
      *((INT32 *)var) = (INT32)val;
      break;
    case OVK_UINT32:
      *((UINT32 *)var) = (UINT32)val;
      break;
    case OVK_INT64:
      *((INT64 *)var) = (UINT64)val;
      break;
    case OVK_UINT64:
      *((UINT64 *)var) = (UINT64)val;
      break;
    default:
      break;
  }
}
예제 #4
0
/* ====================================================================
 * Copy_option
 * underlying routine to copy odesc's to and from memory
 * returns number of bytes copied
 * ====================================================================*/
static INT
Copy_option(OPTION_DESC *odesc, char *container, BOOL save)
{
  void *var = ODESC_variable(odesc);
  size_t sz = 0;

  Is_True(ODESC_can_change_by_pragma(odesc),
	  ("Copy_option, trying to copy option that cannot change"));

  switch (ODESC_kind(odesc)) {
    case OVK_NONE:
    case OVK_BOOL:
      sz = sizeof(BOOL);
      break;
    case OVK_INT32:
    case OVK_UINT32:
      sz = sizeof(INT32);
      break;
    case OVK_INT64:
    case OVK_UINT64:
      sz = sizeof(INT64);
    case OVK_NAME:
    case OVK_SELF:
    case OVK_LIST:
      sz = sizeof(void *);
  }

  if (sz > 0) {
    if (save)
      memcpy(container, var, sz);
    else
      memcpy(var, container, sz);
  }
  return (sz);
}
예제 #5
0
파일: flags.c 프로젝트: Akheon23/nvopencc
void
Set_Option_Internal ( OPTION_GROUP *ogroup, const char *name )
{
  if ( name == NULL ) {
    Set_OGA_internal ( OGROUP_aux (ogroup) );
    return;
  } else {
    OPTION_DESC *o;

    for ( o = OGROUP_options(ogroup);
	  ODESC_kind(o) != OVK_COUNT
       && ODESC_kind(o) != OVK_OLD_COUNT;
	  ++o )
    {
      if ( strcasecmp ( name, ODESC_name(o) ) == 0 ) {
	ODESC_visibility(o) = OV_INTERNAL;
      }
    }
  }
}
예제 #6
0
파일: flags.c 프로젝트: Akheon23/nvopencc
BOOL
Process_Command_Line_Group (char *flag, OPTION_GROUP *opt_groups)
{
    OPTION_GROUP *group;
    char *option, *copy, *cp, *next_cp;
    size_t tidx;
    char sep[3];
    BOOL hasval;
    char *val = NULL;
    BOOL bval;
    INT64 ival;
    OPTION_DESC *odesc, *found, *first_found;
    OPTION_LIST *olist, *ol;

    /* Just in case: */
    Initialize_Option_Groups ( opt_groups );

    /* See whether flag names an option group */
    option = NULL;
    for (group = opt_groups; group && OGROUP_name(group); group++) {
	register INT group_name_len;

	if (flag[0] != *OGROUP_name(group))
	    continue;
      
	group_name_len = strlen(OGROUP_name(group));
      
	if (strncmp(flag, OGROUP_name(group), group_name_len) == 0 &&
	    flag[group_name_len] == OGROUP_separator(group)) {
	    /* We have a match.  Point to first option char
	     * and quit searching.
	     */
	    option = flag + group_name_len + 1;
	    break;
	}
    }

    /* Return failure indication if flag doesn't name an option group */
    if (option == NULL)
	return FALSE;

    cp = copy = strdup ( option );	/* Make a permanent, modifiable copy */
    next_cp = cp;

    /* Set up a separator string: */
    sep[0] = OGROUP_valmarker(group);
    sep[1] = OGROUP_separator(group);
    sep[2] = 0;

#ifdef Is_True_On
    /* Configuration check: make sure each non-NULL abbreviation is
     * actual prefix of option name.  Otherwise, we'll never match.
     */
    for ( odesc=OGROUP_options(group);
	  ODESC_kind(odesc) != OVK_COUNT
       && ODESC_kind(odesc) != OVK_OLD_COUNT;
	  odesc++)
    {
      const char *abbrev = ODESC_abbrev(odesc);
      const char *name = ODESC_name(odesc);
      Is_True ( abbrev == NULL
	     || strncmp(abbrev, name, strlen(abbrev)) == 0,
		( "Option group (%s) configuration error: "
		  "'%s' not prefix of '%s'",
		  OGROUP_name(group), abbrev, name ) );
    }
#endif

    while ( next_cp != NULL ) {
        char this_flag[256];

	cp = next_cp;

	/* Find end of name: */
	tidx = strcspn ( cp, sep );
	next_cp = ( cp[tidx] == 0 ) ? NULL : cp+tidx+1;

	/* If it's a value, extract it: */
	hasval = ( cp[tidx] == OGROUP_valmarker(group) );
	cp[tidx] = 0;
	if ( hasval ) {
	    val = next_cp;
	    /* Don't consider valmarker this time: */
	    tidx = strcspn ( val, &sep[1] );
	    next_cp = ( val[tidx] == 0 ) ? NULL : val+tidx+1;
	    val[tidx] = 0;
	}

	/* Construct string containing only the current flag,
	 * with group name for context.  This lets us emit
	 * clearer error messages.
	 */
	sprintf(this_flag, "%.50s%c%.100s", OGROUP_name(group),
		OGROUP_separator(group), cp);
	if (hasval)
	  sprintf(this_flag+strlen(this_flag), "%c%.100s",
		  OGROUP_valmarker(group), val);

	/* Find the option descriptor: */
	first_found = found = NULL;
	for ( odesc = OGROUP_options(group);
	      !found
	   && ODESC_kind(odesc) != OVK_COUNT
	   && ODESC_kind(odesc) != OVK_OLD_COUNT;
	     odesc++ )
	{
	    /* Matching rules.  If abbreviation is:
	     * (1) NULL - only whole name matches.
	     * (2) Empty string - any non-ambiguous prefix of name matches.
	     * (3) Any other prefix of name - anything between abbrev and whole
	     *     name matches.
	     */
	    if (!ODESC_abbrev(odesc)) {
		/* Rule (1) */
		if (strcasecmp(cp, ODESC_name(odesc)) == 0) found = odesc;
	    } else {
		INT32 alen = strlen(ODESC_abbrev(odesc));
		INT32 clen = strlen(cp);
		if (alen == 0)  {
		    /*
		     * Rule (2).  If matching, start ambiguity check
		     * by setting first_found, unless we're already
		     * checking for ambiguity.
		     */
		    if (strncasecmp(cp, ODESC_name(odesc), clen) == 0) {
			if (!first_found) first_found = odesc;
			else found = odesc;
		    }
		} else {
		    /* Rule (3) */
		    if (strncasecmp(ODESC_abbrev(odesc), cp, alen) == 0 &&
			strncasecmp(cp, ODESC_name(odesc), clen) == 0)
			found = odesc;
		}
	    }
	}

	/* Finish ambiguity check */
	if (first_found) {
	    if (found) {
		ErrMsg(EC_Ambig_In_Grp, cp, OGROUP_name(group), this_flag);
		continue;
	    }
	    found = first_found;
	}

	if ( found == NULL ) {
	    /* Complain: */
	    ErrMsg ( EC_Not_In_Grp, cp, OGROUP_name(group), this_flag );
	} else {
	    ODESC_AUX *aux = ODESC_aux(found);

	    /* Set specified flag if given */
	    if ( ODA_specified(aux) ) *ODA_specified(aux) = TRUE;

	    switch ( ODESC_kind(found) ) {
	    case OVK_NONE:
		if ( hasval ) {
		    ErrMsg (EC_Inv_Grp_Val, cp, OGROUP_name(group), val,
			    this_flag);
		}
		Update_Scalar_Value ( found, (UINT64)TRUE );
		break;

	    case OVK_OBSOLETE:
		ErrMsg ( EC_Obsolete_Opt, this_flag );
		break;

	    case OVK_REPLACED:
		ErrMsg ( EC_Replaced_Opt, this_flag,
			 (char *)ODESC_variable(found) );
		break;

	    case OVK_UNIMPLEMENTED:
		ErrMsg ( EC_Unimp_Opt, this_flag );
		break;

	    case OVK_BOOL:
		if ( hasval ) {
		    bval = ( strcasecmp ( val, "ON" ) == 0
			  || strcasecmp ( val, "TRUE" ) == 0
			  || strcasecmp ( val, "YES" ) == 0
			  || ( strcasecmp ( val, "OFF" ) != 0
			    && strcasecmp ( val, "FALSE" ) != 0
			    && strcasecmp ( val, "NO" ) != 0
			    && strcmp ( val, "0" ) != 0 ) );
		} else {
		    bval = TRUE;
		}
		Update_Scalar_Value ( found, (UINT64)bval );
		break;

	    case OVK_INT32:
	    case OVK_INT64:
	    case OVK_UINT64:
	    case OVK_UINT32:
		if ( ! hasval ) {
		    ival = ODESC_def_val(found);
		} else {
		    char *tval = val;
		    if ((*val < '0' || *val > '9') && *val != '-')
		      ErrMsg(EC_Flag_Int_Expected, this_flag);
		    ival = Get_Numeric_Flag ( &tval,
					     ODESC_min_val(found),
					     ODESC_max_val(found),
					     ODESC_def_val(found),
					     this_flag );
		}
		Update_Scalar_Value ( found, (UINT64)ival );
		break;

#if 0
	    case OVK_INT64:
	    case OVK_UINT64:
		if ( ODESC_min_val(found) < INT32_MIN	||
		    ODESC_max_val(found) > INT32_MAX )
		    {
			ErrMsg ( EC_Unimplemented,
				"Process_Command_Line_Group: "
				"> 32-bit flag values" );
		    }
		if ( ! hasval ) {
		    ival = ODESC_def_val(found);
		} else {
		    char *tval = val;
		    if ((*val < '0' || *val > '9') && *val != '-')
		      ErrMsg(EC_Flag_Int_Expected, this_flag);
		    ival = Get_Numeric_Flag ( &tval,
					     ODESC_min_val(found),
					     ODESC_max_val(found),
					     ODESC_def_val(found),
					     this_flag );
		}
		Update_Scalar_Value ( found, (UINT64)ival );
		break;
#endif

	    case OVK_NAME:
		if ( ! hasval ) {
		    val = "";
		}
		Update_Pointer_Value ( found, strdup (val) );
		break;

	    case OVK_SELF:
		if ( ! hasval ) {
		    val = cp;
		}
		Update_Pointer_Value ( found, strdup (val) );
		break;

	    case OVK_LIST:
		olist =
		    (OPTION_LIST *) calloc ( sizeof(OPTION_LIST), 1 );
		OLIST_val(olist) = val ? strdup ( val ) : NULL;
		OLIST_opt(olist) = ODESC_name(found);
		ol = *(OPTION_LIST **)ODESC_variable(found);

		if ( ol == NULL ) {
		  Update_Pointer_Value ( found, olist );

		} else {
		  while ( OLIST_next(ol) != NULL ) ol = OLIST_next(ol);
		  OLIST_next(ol) = olist;

		  /* This won't actually change the apparent value of
		   * ODA_last, since the head of the list isn't
		   * changing.  So, just mark it modified and set:
		   */
		  Set_ODA_mod ( aux );
		  Set_ODA_set ( aux );
		}
		break;

	    default:
		break;
	    }
	}
    }

    free(copy);
    /* Return success indicator */
    return TRUE;
} /* Process_Command_Line_Group */
예제 #7
0
파일: flags.c 프로젝트: Akheon23/nvopencc
static void
Initialize_Option_Group ( OPTION_GROUP *ogroup )
{
  OGROUP_AUX *ogaux;
  INT16 count, i;
  OPTION_DESC *odesc;
  ODESC_AUX *odaux;

  /* If we've already done it, never mind: */
  if ( OGROUP_aux(ogroup) != NULL ) return;

  /* Count the descriptors in the group, including terminator: */
  count = 1;
  for ( odesc = OGROUP_options(ogroup);
	ODESC_kind(odesc) != OVK_COUNT
     && ODESC_kind(odesc) != OVK_OLD_COUNT;
	++odesc )
  {
    ++count;
  }

  /* Allocate the auxiliary descriptors: */
  ogaux = (OGROUP_AUX *) calloc ( 1, sizeof (OGROUP_AUX) );
  if ( ogaux == NULL ) {
    ErrMsg ( EC_No_Mem, "Initialize_Option_Group: OGROUP_aux" );
  }
  Set_OGROUP_aux ( ogroup, ogaux );
  odaux = (ODESC_AUX *) calloc ( count, sizeof (ODESC_AUX) );
  if ( odaux == NULL ) {
    ErrMsg ( EC_No_Mem, "Initialize_Option_Group: ODESC_aux" );
  }
  OGA_odesc_aux(ogaux) = odaux;
  OGA_count(ogaux) = count-1;	/* Not including terminator */

  /* Initialize the auxiliary option descriptors: */
  for ( i = 0, odesc = OGROUP_options(ogroup);
	i < count;
	++i, ++odesc, ++odaux )
  {
    ODA_specified(odaux) = ODESC_orig_specified(odesc);
    Set_ODESC_aux ( odesc, odaux );
    Duplicate_Value ( odesc, &ODA_orig(odaux) );
    ODA_last(odaux) = ODA_orig(odaux);
  }

  /* Special initialization for OVK_LIST options.  Several such options
   * may use the same variable.  So we make the ODA_primary field of
   * the first one's aux descriptor point to its ODESC, and then we
   * use the same aux descriptor for all the others.  Exception: if
   * the secondary has a different override variable than the primary,
   * they can't share since that moves to the auxiliary descriptor.
   *
   * Do the same for OVK_NAME and OVK_SELF options, taking care of
   * situations like -TARG:isa=mips3 and -TARG:mips3 using the same
   * variable.
   */
  for ( odesc = OGROUP_options(ogroup);
	ODESC_kind(odesc) != OVK_COUNT
     && ODESC_kind(odesc) != OVK_OLD_COUNT;
	++odesc )
  {
    if ( ODA_primary ( ODESC_aux(odesc) ) == NULL
      && ( ODESC_kind(odesc) == OVK_LIST
	|| ODESC_kind(odesc) == OVK_NAME
	|| ODESC_kind(odesc) == OVK_SELF ) )
    {
      OPTION_DESC *sdesc;

      ODA_primary ( ODESC_aux(odesc) ) = odesc;
      for ( sdesc = odesc+1;
	    ODESC_kind(sdesc) != OVK_COUNT
	 && ODESC_kind(sdesc) != OVK_OLD_COUNT;
	    ++sdesc )
      {
	if ( ODESC_variable(sdesc) == ODESC_variable(odesc)
	  && ODESC_specified(sdesc) == ODESC_specified(odesc) )
	{
	  Set_ODESC_aux ( sdesc, ODESC_aux(odesc) );
	}
      }
    }
  }
}
예제 #8
0
파일: flags.c 프로젝트: Akheon23/nvopencc
/* ====================================================================
 * Copy_option
 * underlying routine to copy odesc's to and from memory
 * returns number of bytes copied
 * ====================================================================*/
static INT
Copy_option(OPTION_DESC *odesc, char *container, BOOL save)
{
  void *var = ODESC_variable(odesc);
  Is_True(ODESC_can_change_by_pragma(odesc),
	  ("Copy_option, trying to copy option that cannot change"));

  if (save) {
    switch (ODESC_kind(odesc)) {
      case OVK_NONE:
      case OVK_BOOL:
        *((BOOL *)container) = *((BOOL *)var);
	return sizeof(BOOL);
      case OVK_INT32:
	*((INT32 *)container) = *((INT32 *)var);
	return sizeof(INT32);
      case OVK_UINT32:
	*((UINT32 *)container) = *((UINT32 *)var);
	return sizeof(UINT32);
      case OVK_INT64:
	*((INT64 *)container) = *((INT64 *)var);
	return sizeof(INT64);
      case OVK_UINT64:
	*((UINT64 *)container) = *((UINT64 *)var);
	return sizeof(UINT64);
      case OVK_NAME:
      case OVK_SELF:
	*((char **)container) = *((char **)var);
	return sizeof(char *);
      case OVK_LIST:
	*((OPTION_LIST **)container) = *((OPTION_LIST **)var);
	return sizeof(OPTION_LIST *);
      default: /* INVALID, OBSOLETE, REPLACED, UNIMPLEMENTED */
	return 0;
    }
  } else { /* restore */
    switch (ODESC_kind(odesc)) {
      case OVK_NONE:
      case OVK_BOOL:
        *((BOOL *)var) = *((BOOL *)container);
	return sizeof(BOOL);
      case OVK_INT32:
	*((INT32 *)var) = *((INT32 *)container);
	return sizeof(INT32);
      case OVK_UINT32:
	*((UINT32 *)var) = *((UINT32 *)container);
	return sizeof(UINT32);
      case OVK_INT64:
	*((INT64 *)var) = *((INT64 *)container);
	return sizeof(INT64);
      case OVK_UINT64:
	*((UINT64 *)var) = *((UINT64 *)container);
	return sizeof(UINT64);
      case OVK_NAME:
      case OVK_SELF:
	*((char **)var) = *((char **)container);
	return sizeof(char *);
      case OVK_LIST:
	*((OPTION_LIST **)var) = *((OPTION_LIST **)container);
	return sizeof(OPTION_LIST *);
      default: /* INVALID, OBSOLETE, REPLACED, UNIMPLEMENTED */
	return 0;
    }
  }
}
예제 #9
0
파일: flags.c 프로젝트: Akheon23/nvopencc
void
Print_Option_Group ( FILE *tf, OPTION_GROUP *og, const char *prefix,
		     BOOL internal, BOOL full, BOOL update )
{
  OPTION_DESC *desc = OGROUP_options(og);
  ODESC_AUX *aux;
  OPTION_LIST **this;
  OPTION_LIST *list;
  BOOL option_set = FALSE;
  BOOL visible_option = FALSE;
  char *bar = SBar + 12;	/* shorten it a bit */

  /* Don't print internal groups in user mode: */
  if ( !internal && OGA_internal ( OGROUP_aux(og) ) ) return;

  /* Clear the ODA_PRINTED flags and check for set options: */
  for ( desc = OGROUP_options(og);
	ODESC_kind(desc) != OVK_COUNT
     && ODESC_kind(desc) != OVK_OLD_COUNT;
	desc++ )
  {
    aux = ODESC_aux(desc);
    Reset_ODA_printed ( aux );
    if ( ( internal
	&& ( ODA_set_int(aux) || Modified_Option(desc) ) )
      || ( ! internal
	&& ODESC_visibility(desc) != OV_INTERNAL
	&& ( ODA_set_user(aux) || Modified_Option(desc) ) ) )
    {
      Set_ODA_print(aux);
      option_set = TRUE;
    } else {
      Reset_ODA_print(aux);
      if ( ODESC_visibility(desc) != OV_INTERNAL ) {
	visible_option = TRUE;
      }
    }
  }

  /* Is there anything to print? */
  if ( ! ( option_set || full ) ) return;
  if ( ! ( option_set || internal || visible_option ) ) return;

  /* Print a header: */
  fprintf ( tf, "\n%s%s%s -%s Option Group\n",
	    prefix, bar, prefix, OGROUP_name(og) );
  if ( OGROUP_description(og) != NULL ) {
    fprintf ( tf, "%s\t%s\n", prefix, OGROUP_description(og) );
  }
  fprintf ( tf, "%s%s", prefix, bar );

  for ( desc = OGROUP_options(og);
	ODESC_kind(desc) != OVK_COUNT
     && ODESC_kind(desc) != OVK_OLD_COUNT;
	desc++ )
  {
    char mchar;

    aux = ODESC_aux(desc);
    if ( ! ODA_print(aux) && ! full ) continue;
    if ( ! internal && ODESC_visibility(desc) == OV_INTERNAL ) continue;

    /* Mark modified options with '#', set options with '=': */
    if ( ( ! internal && (ODA_mod_user(aux) || Modified_Option(desc) ) )
      || ( internal && (ODA_mod_int(aux) || Modified_Option(desc) ) ) )
    {
      mchar = '#';
    } else if ( ( ! internal && ODA_set_user(aux) )
	     || (   internal && ODA_set_int(aux) ) )
    {
      mchar = '=';
    } else {
      mchar = ' ';
    }

    fprintf ( tf, "%s%c %-20s= ", prefix, mchar, ODESC_name(desc));

    switch (ODESC_kind(desc)) {
    case OVK_BOOL:
	fprintf ( tf, "%s", *((BOOL *) ODESC_variable(desc)) ?
		 "ON" : "OFF");
	break;
    case OVK_INT32:
	fprintf ( tf, "%d", *((INT32 *) ODESC_variable(desc)));
	break;
    case OVK_INT64:
	fprintf ( tf, "%lld", *((INT64 *) ODESC_variable(desc)));
	break;
    case OVK_UINT32:
	fprintf ( tf, "%u", *((UINT32 *) ODESC_variable(desc)));
	break;
    case OVK_UINT64:
	fprintf ( tf, "%llu", *((UINT64 *) ODESC_variable(desc)));
	break;

    case OVK_NAME:
    case OVK_SELF:
	/* These are likely to be repeasted, e.g. for
	 * -TARG:isa=mips3 and -TARG:mips3.  So check whether this
	 * is the primary, and just refer to it from secondaries:
	 */
	if ( ODESC_primary(desc) == desc
	  || ODESC_primary(desc) == NULL  )
	{
#ifdef KEY /* bug 12020: The compiler may change the fprintf to fputs,
	      which cannot handle null. */
	  char ** var = (char **) ODESC_variable(desc);
	  if ( *var != NULL )
	    fprintf ( tf, "%s", *var);
#else
	  fprintf ( tf, "%s", *((char **) ODESC_variable(desc)));
#endif
	} else {
	  fprintf ( tf, " (See '%s' above)",
		    ODESC_name(ODESC_primary(desc)) );
	}
	break;

    case OVK_LIST:
	/* Lists are likely to be repeated for multiple options.
	 * If the primary isn't this option, we have that situation,
	 * and we simply refer to the primary:
	 */
	if ( ODESC_primary(desc) == desc
	  || ODESC_primary(desc) == NULL  )
	{
	  char sep = ' ';

	  this = (OPTION_LIST **)ODESC_variable(desc);
	  for ( list = *this; list != NULL; list = OLIST_next(list) ) {
	    fprintf ( tf, "%c%s%c%s", sep, OLIST_opt(list),
		      OGROUP_valmarker(og), OLIST_val(list) );
	    sep = OGROUP_separator(og);
	  }
	} else {
	  fprintf ( tf, " (See '%s' above)",
		    ODESC_name(ODESC_primary(desc)) );
	}
	break;

    default:
	break;
    }