/* ==================================================================== * * 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; } }
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) ); }
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; } }
/* ==================================================================== * 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); }
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; } } } }
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 */
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) ); } } } } }
/* ==================================================================== * 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; } } }
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; }