From patchwork Wed Sep 1 19:23:30 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: Option alias support for .opt files Date: Wed, 01 Sep 2010 09:23:30 -0000 From: Joseph S. Myers X-Patchwork-Id: 63409 Message-Id: To: gcc-patches@gcc.gnu.org This patch adds an option alias facility for .opt files. It doesn't cover quite everything needed to replace translate_options - remaining pieces will be in subsequent patches - but it does suffice to handle various existing option aliases. When an option is an alias, no OPT_* enum value is generated for it and all code dealing with decoded options only needs to deal with the canonical option, not with the alias. In addition, specs only need to deal with the canonical form of the option. The canonical option fields in cl_decoded_option structures now really do represent a canonical form rather than what was passed in argv; option arguments for options accepting both joined and separate arguments are canonically considered to be separate. (To avoid possible problems with some linkers, gcc.c makes sure to use a joined form of -L options for specs; this appears to be the only existing option likely to have such issues. The use of separate arguments as canonical incidentally fixes PR 44076, an issue with a "%{!MT:...}" spec not matching -MT options with joined argument.) By not creating OPT_* enum names for aliases, it is no longer necessary for the OPT_* enum names to have special cases for options with forms ending both "-" and "=". -Werror= will handle aliases - thus, both -Werror=comment and -Werror=comments will work the same, whereas only one would work before (diagnostics will say "-Werror=comment" as the enabling option regardless of which was actually passed, but that's a minor issue). Various existing options are marked as aliases where appropriate. In the Java case this will cause some options to be accepted by jc1 that were previously only accepted by the driver; I think this is appropriate (there is no reason for options logically meaningful to both to be accepted by one only). Bootstrapped with no regressions on x86_64-unknown-linux-gnu. OK to commit? 2010-09-01 Joseph Myers PR driver/44076 * opts.h (struct cl_option): Add alias_arg, neg_alias_arg and alias_target fields. * opt-functions.awk (opt_sanitized_name): Don't handle finline-limit=, Wlarger-than= and ftemplate-depth= specially. * optc-gen.awk: Generate alias fields. * opth-gen.awk: Explicitly give values for OPT_* enum constants. Don't generate such constants for aliases. * opts-common.c (generate_canonical_option): New. (decode_cmdline_option): Handle aliases. Use generate_canonical_option for known options instead of copying the input option text. * doc/options.texi (Alias): Document. * common.opt (W, Wlarger-than-, aux-info=, finline-limit-, fstack-check, specs): Mark as aliases. * gcc.c (driver_handle_option): Canonicalize -L options to joined arguments. (driver_handle_option): Don't handle OPT_specs. * opts.c (common_handle_option): Don't handle options marked as aliases. (enable_warning_as_error): Handle aliases. * stor-layout.c (layout_decl): Use OPT_Wlarger_than_ instead of OPT_Wlarger_than_eq. * tree-optimize.c (tree_rest_of_compilation): Use OPT_Wlarger_than_ instead of OPT_Wlarger_than_eq. c-family: 2010-09-01 Joseph Myers * c.opt (Wcomments, Werror-implicit-function-declaration, ftemplate-depth-, std=c89, std=c9x, std=gnu89, std=gnu9x, std=iso9899:1990, std=iso9899:1999, std=iso9899:199x): Mark as aliases. * c-common.c (option_codes): Use OPT_Wcomment instead of OPT_Wcomments. * c-opts.c (warning_as_error_callback, c_common_handle_option): Don't handle options marked as aliases. java: 2010-09-01 Joseph Myers * lang.opt (CLASSPATH, bootclasspath, classpath, encoding, fCLASSPATH=): Mark as Java options and as aliases. * jvspec.c (jvgenmain_spec): Don't handle -fCLASSPATH*. (lang_specific_driver): Don't handle options marked as aliases. * lang.c (java_handle_option): Don't handle OPT_fCLASSPATH_. testsuite: 2010-09-01 Joseph Myers * gcc.dg/cpp/warn-comments-3.c: New. Based on warn-comments-2.c but using -Werror=comment. * gcc.dg/cpp/warn-comments.c, gcc.dg/cpp/warn-comments-2.c: Adjust expected error messages. Index: gcc/doc/options.texi =================================================================== --- gcc/doc/options.texi (revision 163669) +++ gcc/doc/options.texi (working copy) @@ -247,6 +247,32 @@ The main purpose of this property is to The first option should use @samp{Mask(@var{name})} and the others should use @samp{Mask(@var{name}) MaskExists}. +@item Alias(@var{opt}) +@itemx Alias(@var{opt}, @var{arg}) +@itemx Alias(@var{opt}, @var{posarg}, @var{negarg}) +The option is an alias for @option{-@var{opt}}. In the first form, +any argument passed to the alias is considered to be passed to +@option{-@var{opt}}, and @option{-@var{opt}} is considered to be +negated if the alias is used in negated form. In the second form, the +alias may not be negated or have an argument, and @var{posarg} is +considered to be passed as an argument to @option{-@var{opt}}. In the +third form, the alias may not have an argument, if the alias is used +in the positive form then @var{posarg} is considered to be passed to +@option{-@var{opt}}, and if the alias is used in the negative form +then @var{negarg} is considered to be passed to @option{-@var{opt}}. + +Aliases should not specify @code{Var} or @code{Mask} or +@code{UInteger}. Aliases should normally specify the same languages +as the target of the alias; the flags on the target will be used to +determine any diagnostic for use of an option for the wrong language, +while those on the alias will be used to identify what command-line +text is the option and what text is any argument to that option. + +When an @code{Alias} definition is used for an option, driver specs do +not need to handle it and no @samp{OPT_} enumeration value is defined +for it; only the canonical form of the option will be seen in those +places. + @item Report The state of the option should be printed by @option{-fverbose-asm}. Index: gcc/opts-common.c =================================================================== --- gcc/opts-common.c (revision 163669) +++ gcc/opts-common.c (working copy) @@ -144,6 +144,58 @@ option_ok_for_language (const struct cl_ return true; } + +/* Fill in the canonical option part of *DECODED with an option + described by OPT_INDEX, ARG and VALUE. */ + +static void +generate_canonical_option (size_t opt_index, const char *arg, int value, + struct cl_decoded_option *decoded) +{ + const struct cl_option *option = &cl_options[opt_index]; + const char *opt_text = option->opt_text; + + if (value == 0 + && !(option->flags & CL_REJECT_NEGATIVE) + && (opt_text[1] == 'W' || opt_text[1] == 'f' || opt_text[1] == 'm')) + { + char *t = XNEWVEC (char, option->opt_len + 5); + t[0] = '-'; + t[1] = opt_text[1]; + t[2] = 'n'; + t[3] = 'o'; + t[4] = '-'; + memcpy (t + 5, opt_text + 2, option->opt_len); + opt_text = t; + } + + decoded->canonical_option[2] = NULL; + decoded->canonical_option[3] = NULL; + + if (arg) + { + if (option->flags & CL_SEPARATE) + { + decoded->canonical_option[0] = opt_text; + decoded->canonical_option[1] = arg; + decoded->canonical_option_num_elements = 2; + } + else + { + gcc_assert (option->flags & CL_JOINED); + decoded->canonical_option[0] = concat (opt_text, arg, NULL); + decoded->canonical_option[1] = NULL; + decoded->canonical_option_num_elements = 1; + } + } + else + { + decoded->canonical_option[0] = opt_text; + decoded->canonical_option[1] = NULL; + decoded->canonical_option_num_elements = 1; + } +} + /* Decode the switch beginning at ARGV for the language indicated by LANG_MASK (including CL_COMMON and CL_TARGET if applicable), into the structure *DECODED. Returns the number of switches @@ -245,13 +297,64 @@ decode_cmdline_option (const char **argv result = 1; } + if (arg == NULL && (separate_arg_flag || joined_arg_flag)) + errors |= CL_ERR_MISSING_ARG; + + /* Is this option an alias? */ + if (option->alias_target != N_OPTS) + { + size_t new_opt_index = option->alias_target; + const struct cl_option *new_option = &cl_options[new_opt_index]; + + /* The new option must not be an alias itself. */ + gcc_assert (new_option->alias_target == N_OPTS); + + if (option->neg_alias_arg) + { + gcc_assert (option->alias_arg != NULL); + gcc_assert (arg == NULL); + if (value) + arg = option->alias_arg; + else + arg = option->neg_alias_arg; + value = 1; + } + else if (option->alias_arg) + { + gcc_assert (value == 1); + gcc_assert (arg == NULL); + arg = option->alias_arg; + } + + opt_index = new_opt_index; + option = new_option; + + if (value == 0) + gcc_assert (!(option->flags & CL_REJECT_NEGATIVE)); + + /* Recompute what arguments are allowed. */ + separate_arg_flag = ((option->flags & CL_SEPARATE) + && !((option->flags & CL_NO_DRIVER_ARG) + && (lang_mask & CL_DRIVER))); + joined_arg_flag = (option->flags & CL_JOINED) != 0; + + if (!(errors & CL_ERR_MISSING_ARG)) + { + if (separate_arg_flag || joined_arg_flag) + gcc_assert (arg != NULL); + else + gcc_assert (arg == NULL); + } + + /* Recheck for disabled options. */ + if (option->flags & CL_DISABLED) + errors |= CL_ERR_DISABLED; + } + /* Check if this is a switch for a different front end. */ if (!option_ok_for_language (option, lang_mask)) errors |= CL_ERR_WRONG_LANG; - if (arg == NULL && (separate_arg_flag || joined_arg_flag)) - errors |= CL_ERR_MISSING_ARG; - /* If the switch takes an integer, convert it. */ if (arg && (option->flags & CL_UINTEGER)) { @@ -296,12 +399,17 @@ decode_cmdline_option (const char **argv { if (i < result) { - decoded->canonical_option[i] = argv[i]; + if (opt_index == OPT_SPECIAL_unknown) + decoded->canonical_option[i] = argv[i]; + else + decoded->canonical_option[i] = NULL; total_len += strlen (argv[i]) + 1; } else decoded->canonical_option[i] = NULL; } + if (opt_index != OPT_SPECIAL_unknown) + generate_canonical_option (opt_index, arg, value, decoded); decoded->orig_option_with_args_text = p = XNEWVEC (char, total_len); for (i = 0; i < result; i++) { @@ -571,39 +679,26 @@ generate_option (size_t opt_index, const decoded->opt_index = opt_index; decoded->arg = arg; - decoded->canonical_option[2] = NULL; - decoded->canonical_option[3] = NULL; decoded->value = value; decoded->errors = (option_ok_for_language (option, lang_mask) ? 0 : CL_ERR_WRONG_LANG); - if (arg) + generate_canonical_option (opt_index, arg, value, decoded); + switch (decoded->canonical_option_num_elements) { - if (option->flags & CL_SEPARATE) - { - decoded->orig_option_with_args_text = concat (option->opt_text, " ", - arg, NULL); - decoded->canonical_option[0] = option->opt_text; - decoded->canonical_option[1] = arg; - decoded->canonical_option_num_elements = 2; - } - else - { - gcc_assert (option->flags & CL_JOINED); - decoded->orig_option_with_args_text = concat (option->opt_text, arg, - NULL); - decoded->canonical_option[0] = decoded->orig_option_with_args_text; - decoded->canonical_option[1] = NULL; - decoded->canonical_option_num_elements = 1; - } - } - else - { - decoded->orig_option_with_args_text = option->opt_text; - decoded->canonical_option[0] = option->opt_text; - decoded->canonical_option[1] = NULL; - decoded->canonical_option_num_elements = 1; + case 1: + decoded->orig_option_with_args_text = decoded->canonical_option[0]; + break; + + case 2: + decoded->orig_option_with_args_text + = concat (decoded->canonical_option[0], " ", + decoded->canonical_option[1], NULL); + break; + + default: + gcc_unreachable (); } } Index: gcc/c-family/c.opt =================================================================== --- gcc/c-family/c.opt (revision 163669) +++ gcc/c-family/c.opt (working copy) @@ -164,7 +164,7 @@ C ObjC C++ ObjC++ Warning Warn about possibly nested block comments, and C++ comments spanning more than one physical line Wcomments -C ObjC C++ ObjC++ Warning +C ObjC C++ ObjC++ Warning Alias(Wcomment) Synonym for -Wcomment Wconversion @@ -216,7 +216,7 @@ C ObjC C++ ObjC++ ; Documented in common.opt Werror-implicit-function-declaration -C ObjC RejectNegative Warning +C ObjC RejectNegative Warning Alias(Werror=, implicit-function-declaration) This switch is deprecated; use -Werror=implicit-function-declaration instead Wfloat-equal @@ -804,7 +804,7 @@ C ObjC C++ ObjC++ Joined RejectNegative -ftabstop= Distance between tab stops for column reporting ftemplate-depth- -C++ ObjC++ Joined RejectNegative UInteger Undocumented +C++ ObjC++ Joined RejectNegative Undocumented Alias(ftemplate-depth=) ftemplate-depth= C++ ObjC++ Joined RejectNegative UInteger @@ -972,7 +972,7 @@ C ObjC Conform to the ISO 201X C standard draft (experimental and incomplete support) std=c89 -C ObjC +C ObjC Alias(std=c90) Conform to the ISO 1990 C standard std=c90 @@ -984,7 +984,7 @@ C ObjC Conform to the ISO 1999 C standard std=c9x -C ObjC +C ObjC Alias(std=c99) Deprecated in favor of -std=c99 std=gnu++98 @@ -1003,7 +1003,7 @@ C ObjC Conform to the ISO 201X C standard draft with GNU extensions (experimental and incomplete support) std=gnu89 -C ObjC +C ObjC Alias(std=gnu90) Conform to the ISO 1990 C standard with GNU extensions std=gnu90 @@ -1015,11 +1015,11 @@ C ObjC Conform to the ISO 1999 C standard with GNU extensions std=gnu9x -C ObjC +C ObjC Alias(std=gnu99) Deprecated in favor of -std=gnu99 std=iso9899:1990 -C ObjC +C ObjC Alias(std=c90) Conform to the ISO 1990 C standard std=iso9899:199409 @@ -1027,11 +1027,11 @@ C ObjC Conform to the ISO 1990 C standard as amended in 1994 std=iso9899:1999 -C ObjC +C ObjC Alias(std=c99) Conform to the ISO 1999 C standard std=iso9899:199x -C ObjC +C ObjC Alias(std=c99) Deprecated in favor of -std=iso9899:1999 traditional-cpp Index: gcc/c-family/c-opts.c =================================================================== --- gcc/c-family/c-opts.c (revision 163669) +++ gcc/c-family/c-opts.c (working copy) @@ -161,7 +161,6 @@ warning_as_error_callback (int option_in break; case OPT_Wcomment: - case OPT_Wcomments: cpp_opts->warn_comments = 1; break; @@ -493,7 +492,6 @@ c_common_handle_option (size_t scode, co break; case OPT_Wcomment: - case OPT_Wcomments: cpp_opts->warn_comments = value; break; @@ -521,13 +519,6 @@ c_common_handle_option (size_t scode, co global_dc->warning_as_error_requested = value; break; - case OPT_Werror_implicit_function_declaration: - /* For backward compatibility, this is the same as - -Werror=implicit-function-declaration. */ - enable_warning_as_error ("implicit-function-declaration", value, - CL_C | CL_ObjC, handlers); - break; - case OPT_Wformat: set_Wformat (value); break; @@ -752,8 +743,6 @@ c_common_handle_option (size_t scode, co break; case OPT_ftemplate_depth_: - /* Kept for backwards compatibility. */ - case OPT_ftemplate_depth_eq: max_tinst_depth = value; break; @@ -865,30 +854,23 @@ c_common_handle_option (size_t scode, co set_std_cxx0x (code == OPT_std_c__0x /* ISO */); break; - case OPT_std_c89: case OPT_std_c90: - case OPT_std_iso9899_1990: case OPT_std_iso9899_199409: if (!preprocessing_asm_p) set_std_c89 (code == OPT_std_iso9899_199409 /* c94 */, true /* ISO */); break; - case OPT_std_gnu89: case OPT_std_gnu90: if (!preprocessing_asm_p) set_std_c89 (false /* c94 */, false /* ISO */); break; case OPT_std_c99: - case OPT_std_c9x: - case OPT_std_iso9899_1999: - case OPT_std_iso9899_199x: if (!preprocessing_asm_p) set_std_c99 (true /* ISO */); break; case OPT_std_gnu99: - case OPT_std_gnu9x: if (!preprocessing_asm_p) set_std_c99 (false /* ISO */); break; Index: gcc/c-family/c-common.c =================================================================== --- gcc/c-family/c-common.c (revision 163669) +++ gcc/c-family/c-common.c (working copy) @@ -8150,7 +8150,7 @@ struct reason_option_codes_t static const struct reason_option_codes_t option_codes[] = { {CPP_W_DEPRECATED, OPT_Wdeprecated}, - {CPP_W_COMMENTS, OPT_Wcomments}, + {CPP_W_COMMENTS, OPT_Wcomment}, {CPP_W_TRIGRAPHS, OPT_Wtrigraphs}, {CPP_W_MULTICHAR, OPT_Wmultichar}, {CPP_W_TRADITIONAL, OPT_Wtraditional}, Index: gcc/java/jvspec.c =================================================================== --- gcc/java/jvspec.c (revision 163669) +++ gcc/java/jvspec.c (working copy) @@ -69,7 +69,7 @@ static const char jvgenmain_spec[] = %alias_target != N_OPTS) + option_index = option->alias_target; diagnostic_classify_diagnostic (global_dc, option_index, kind, UNKNOWN_LOCATION); if (kind == DK_ERROR) Index: gcc/opts.h =================================================================== --- gcc/opts.h (revision 163669) +++ gcc/opts.h (working copy) @@ -45,6 +45,9 @@ struct cl_option const char *opt_text; const char *help; const char *missing_argument_error; + const char *alias_arg; + const char *neg_alias_arg; + unsigned short alias_target; unsigned short back_chain; unsigned char opt_len; int neg_index; Index: gcc/optc-gen.awk =================================================================== --- gcc/optc-gen.awk (revision 163669) +++ gcc/optc-gen.awk (working copy) @@ -201,6 +201,36 @@ for (i = 0; i < n_opts; i++) { else missing_arg_error = quote missing_arg_error quote + alias_arg = opt_args("Alias", flags[i]) + if (alias_arg == "") { + alias_data = "NULL, NULL, N_OPTS" + } else { + alias_opt = nth_arg(0, alias_arg) + alias_posarg = nth_arg(1, alias_arg) + alias_negarg = nth_arg(2, alias_arg) + + if (var_ref(opts[i], flags[i]) != "0") + print "#error Alias setting variable" + + if (alias_posarg != "" && alias_negarg == "") { + if (!flag_set_p("RejectNegative", flags[i]) \ + && opts[i] ~ "^[Wfm]") + print "#error Alias with single argument " \ + "allowing negative form" + } + + alias_opt = opt_enum(alias_opt) + if (alias_posarg == "") + alias_posarg = "NULL" + else + alias_posarg = quote alias_posarg quote + if (alias_negarg == "") + alias_negarg = "NULL" + else + alias_negarg = quote alias_negarg quote + alias_data = alias_posarg ", " alias_negarg ", " alias_opt + } + neg = opt_args("Negative", flags[i]); if (neg != "") idx = indices[neg] @@ -216,9 +246,9 @@ for (i = 0; i < n_opts; i++) { } # Split the printf after %u to work around an ia64-hp-hpux11.23 # awk bug. - printf(" { %c-%s%c,\n %s,\n %s,\n %s, %u,", + printf(" { %c-%s%c,\n %s,\n %s,\n %s, %s, %u,", quote, opts[i], quote, hlp, missing_arg_error, - back_chain[i], len) + alias_data, back_chain[i], len) printf(" %d,\n", idx) condition = opt_args("Condition", flags[i]) cl_flags = switch_flags(flags[i]) Index: gcc/stor-layout.c =================================================================== --- gcc/stor-layout.c (revision 163669) +++ gcc/stor-layout.c (working copy) @@ -675,9 +675,9 @@ layout_decl (tree decl, unsigned int kno int size_as_int = TREE_INT_CST_LOW (size); if (compare_tree_int (size, size_as_int) == 0) - warning (OPT_Wlarger_than_eq, "size of %q+D is %d bytes", decl, size_as_int); + warning (OPT_Wlarger_than_, "size of %q+D is %d bytes", decl, size_as_int); else - warning (OPT_Wlarger_than_eq, "size of %q+D is larger than %wd bytes", + warning (OPT_Wlarger_than_, "size of %q+D is larger than %wd bytes", decl, larger_than_size); } } Index: gcc/opth-gen.awk =================================================================== --- gcc/opth-gen.awk (revision 163669) +++ gcc/opth-gen.awk (working copy) @@ -321,6 +321,7 @@ print "{" for (i = 0; i < n_opts; i++) back_chain[i] = "N_OPTS"; +enum_value = 0 for (i = 0; i < n_opts; i++) { # Combine the flags of identical switches. Switches # appear many times if they are handled by many front @@ -332,6 +333,12 @@ for (i = 0; i < n_opts; i++) { len = length (opts[i]); enum = opt_enum(opts[i]) + enum_string = enum " = " enum_value "," + + # Aliases do not get enumeration names. + if (flag_set_p("Alias.*", flags[i])) { + enum_string = "/* " enum_string " */" + } # If this switch takes joined arguments, back-chain all # subsequent switches to it for which it is a prefix. If @@ -346,7 +353,8 @@ for (i = 0; i < n_opts; i++) { } } - s = substr(" ", length (enum)) + s = substr(" ", + length (enum_string)) if (i + 1 == n_opts) comma = "" @@ -355,7 +363,8 @@ for (i = 0; i < n_opts; i++) { else hlp = "N_(\"" help[i] "\")"; - print " " enum "," s "/* -" opts[i] " */" + print " " enum_string s "/* -" opts[i] " */" + enum_value++ } print " N_OPTS," Index: gcc/common.opt =================================================================== --- gcc/common.opt (revision 163669) +++ gcc/common.opt (working copy) @@ -88,7 +88,7 @@ S Driver W -Common RejectNegative Var(extra_warnings) Warning +Common RejectNegative Warning Alias(Wextra) This switch is deprecated; use -Wextra instead Wa, @@ -153,7 +153,7 @@ Common Var(warn_inline) Warning Warn when an inlined function cannot be inlined Wlarger-than- -Common RejectNegative Joined UInteger Warning Undocumented +Common RejectNegative Joined Warning Undocumented Alias(Wlarger-than=) Wlarger-than= Common RejectNegative Joined UInteger Warning @@ -301,7 +301,7 @@ Common Separate -aux-info Emit declaration information into aux-info= -Common Joined +Common Joined Alias(aux-info) auxbase Common Separate RejectDriver @@ -750,7 +750,7 @@ Common Report Var(flag_inline_functions_ Integrate functions called once into their callers finline-limit- -Common RejectNegative Joined UInteger +Common RejectNegative Joined Alias(finline-limit=) finline-limit= Common RejectNegative Joined UInteger @@ -1259,7 +1259,7 @@ Common Report RejectNegative Joined -fstack-check=[no|generic|specific] Insert stack checking code into the program fstack-check -Common Report +Common Alias(fstack-check=, specific, no) Insert stack checking code into the program. Same as -fstack-check=specific fstack-limit @@ -1755,7 +1755,7 @@ shared-libgcc Driver specs -Driver Separate +Driver Separate Alias(specs=) specs= Driver Joined Index: gcc/tree-optimize.c =================================================================== --- gcc/tree-optimize.c (revision 163669) +++ gcc/tree-optimize.c (working copy) @@ -477,10 +477,10 @@ tree_rest_of_compilation (tree fndecl) = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type)); if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0) - warning (OPT_Wlarger_than_eq, "size of return value of %q+D is %u bytes", + warning (OPT_Wlarger_than_, "size of return value of %q+D is %u bytes", fndecl, size_as_int); else - warning (OPT_Wlarger_than_eq, "size of return value of %q+D is larger than %wd bytes", + warning (OPT_Wlarger_than_, "size of return value of %q+D is larger than %wd bytes", fndecl, larger_than_size); } } Index: gcc/opt-functions.awk =================================================================== --- gcc/opt-functions.awk (revision 163669) +++ gcc/opt-functions.awk (working copy) @@ -201,9 +201,6 @@ function var_ref(name, flags) # Given the option called NAME return a sanitized version of its name. function opt_sanitized_name(name) { - if (name == "finline-limit=" || name == "Wlarger-than=" \ - || name == "ftemplate-depth=") - name = name "eq" if (name == "gdwarf+") name = "gdwarfplus" gsub ("[^A-Za-z0-9]", "_", name)