* support/cpp2 renamed to support/cpp
[fw/sdcc] / support / cpp / opts.c
diff --git a/support/cpp/opts.c b/support/cpp/opts.c
new file mode 100644 (file)
index 0000000..178c558
--- /dev/null
@@ -0,0 +1,625 @@
+/* Command line option handling.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
+   Contributed by Neil Booth.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "intl.h"
+#include "opts.h"
+#include "options.h"
+
+/* True if we should exit after parsing options.  */
+bool exit_after_options;
+
+/* Treat warnings as errors.  -Werror.  */
+bool warnings_are_errors;
+
+/* Don't suppress warnings from system headers.  -Wsystem-headers.  */
+bool warn_system_headers;
+
+/* Columns of --help display.  */
+static unsigned int columns = 80;
+
+/* What to print when a switch has no documentation.  */
+static const char undocumented_msg[] = N_("This switch lacks documentation");
+
+/* Input file names.  */
+const char **in_fnames;
+unsigned num_in_fnames;
+
+static int common_handle_option (size_t scode, const char *arg, int value);
+static unsigned int handle_option (const char **argv, unsigned int lang_mask);
+static char *write_langs (unsigned int lang_mask);
+static void complain_wrong_lang (const char *, const struct cl_option *,
+                                unsigned int lang_mask);
+static void handle_options (unsigned int, const char **, unsigned int);
+static void wrap_help (const char *help, const char *item, unsigned int);
+static void print_help (void);
+static void print_filtered_help (unsigned int);
+static unsigned int print_switch (const char *text, unsigned int indent);
+
+/* If ARG is a non-negative integer made up solely of digits, return its
+   value, otherwise return -1.  */
+static int
+integral_argument (const char *arg)
+{
+  const char *p = arg;
+
+  while (*p && ISDIGIT (*p))
+    p++;
+
+  if (*p == '\0')
+    return atoi (arg);
+
+  return -1;
+}
+
+/* Return a malloced slash-separated list of languages in MASK.  */
+static char *
+write_langs (unsigned int mask)
+{
+  unsigned int n = 0, len = 0;
+  const char *lang_name;
+  char *result;
+
+  for (n = 0; (lang_name = lang_names[n]) != 0; n++)
+    if (mask & (1U << n))
+      len += strlen (lang_name) + 1;
+
+  result = XNEWVEC (char, len);
+  len = 0;
+  for (n = 0; (lang_name = lang_names[n]) != 0; n++)
+    if (mask & (1U << n))
+      {
+       if (len)
+         result[len++] = '/';
+       strcpy (result + len, lang_name);
+       len += strlen (lang_name);
+      }
+
+  result[len] = 0;
+
+  return result;
+}
+
+/* Complain that switch OPT_INDEX does not apply to this front end.  */
+static void
+complain_wrong_lang (const char *text, const struct cl_option *option,
+                    unsigned int lang_mask)
+{
+  char *ok_langs, *bad_lang;
+
+  ok_langs = write_langs (option->flags);
+  bad_lang = write_langs (lang_mask);
+
+  /* Eventually this should become a hard error IMO.  */
+  warning (0, "command line option \"%s\" is valid for %s but not for %s",
+          text, ok_langs, bad_lang);
+
+  free (ok_langs);
+  free (bad_lang);
+}
+
+/* Handle the switch beginning at ARGV for the language indicated by
+   LANG_MASK.  Returns the number of switches consumed.  */
+static unsigned int
+handle_option (const char **argv, unsigned int lang_mask)
+{
+  size_t opt_index;
+  const char *opt, *arg = 0;
+  char *dup = 0;
+  int value = 1;
+  unsigned int result = 0;
+  const struct cl_option *option;
+
+  opt = argv[0];
+
+  opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
+  if (opt_index == cl_options_count
+      && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm')
+      && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-')
+    {
+      /* Drop the "no-" from negative switches.  */
+      size_t len = strlen (opt) - 3;
+
+      dup = XNEWVEC (char, len + 1);
+      dup[0] = '-';
+      dup[1] = opt[1];
+      memcpy (dup + 2, opt + 5, len - 2 + 1);
+      opt = dup;
+      value = 0;
+      opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
+    }
+
+  if (opt_index == cl_options_count)
+    goto done;
+
+  option = &cl_options[opt_index];
+
+  /* Reject negative form of switches that don't take negatives as
+     unrecognized.  */
+  if (!value && (option->flags & CL_REJECT_NEGATIVE))
+    goto done;
+
+  /* We've recognized this switch.  */
+  result = 1;
+
+  /* Check to see if the option is disabled for this configuration.  */
+  if (option->flags & CL_DISABLED)
+    {
+      error ("command line option \"%s\""
+            " is not supported by this configuration", opt);
+      goto done;
+    }
+
+  /* Sort out any argument the switch takes.  */
+  if (option->flags & CL_JOINED)
+    {
+      /* Have arg point to the original switch.  This is because
+        some code, such as disable_builtin_function, expects its
+        argument to be persistent until the program exits.  */
+      arg = argv[0] + cl_options[opt_index].opt_len + 1;
+      if (!value)
+       arg += strlen ("no-");
+
+      if (*arg == '\0' && !(option->flags & CL_MISSING_OK))
+       {
+         if (option->flags & CL_SEPARATE)
+           {
+             arg = argv[1];
+             result = 2;
+           }
+         else
+           /* Missing argument.  */
+           arg = NULL;
+       }
+    }
+  else if (option->flags & CL_SEPARATE)
+    {
+      arg = argv[1];
+      result = 2;
+    }
+
+  /* Now we've swallowed any potential argument, complain if this
+     is a switch for a different front end.  */
+  if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET)))
+    {
+      complain_wrong_lang (argv[0], option, lang_mask);
+      goto done;
+    }
+
+  if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE)))
+    {
+      if (!lang_hooks.missing_argument (opt, opt_index))
+       error ("missing argument to \"%s\"", opt);
+      goto done;
+    }
+
+  /* If the switch takes an integer, convert it.  */
+  if (arg && (option->flags & CL_UINTEGER))
+    {
+      value = integral_argument (arg);
+      if (value == -1)
+       {
+         error ("argument to \"%s\" should be a non-negative integer",
+                option->opt_text);
+         goto done;
+       }
+    }
+
+  if (option->flag_var)
+    switch (option->var_type)
+      {
+      case CLVC_BOOLEAN:
+       *(int *) option->flag_var = value;
+       break;
+
+      case CLVC_EQUAL:
+       *(int *) option->flag_var = (value
+                                    ? option->var_value
+                                    : !option->var_value);
+       break;
+
+      case CLVC_BIT_CLEAR:
+      case CLVC_BIT_SET:
+       if ((value != 0) == (option->var_type == CLVC_BIT_SET))
+         *(int *) option->flag_var |= option->var_value;
+       else
+         *(int *) option->flag_var &= ~option->var_value;
+       ////if (option->flag_var == &target_flags)
+       ////  target_flags_explicit |= option->var_value;
+       break;
+
+      case CLVC_STRING:
+       *(const char **) option->flag_var = arg;
+       break;
+      }
+
+  if (option->flags & lang_mask)
+    if (lang_hooks.handle_option (opt_index, arg, value) == 0)
+      result = 0;
+
+  if (result && (option->flags & CL_COMMON))
+    if (common_handle_option (opt_index, arg, value) == 0)
+      result = 0;
+
+  ////if (result && (option->flags & CL_TARGET))
+  ////  if (!targetm.handle_option (opt_index, arg, value))
+  ////    result = 0;
+
+ done:
+  if (dup)
+    free (dup);
+  return result;
+}
+
+/* Handle FILENAME from the command line.  */
+static void
+add_input_filename (const char *filename)
+{
+  num_in_fnames++;
+  in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0]));
+  in_fnames[num_in_fnames - 1] = filename;
+}
+
+/* Decode and handle the vector of command line options.  LANG_MASK
+   contains has a single bit set representing the current
+   language.  */
+static void
+handle_options (unsigned int argc, const char **argv, unsigned int lang_mask)
+{
+  unsigned int n, i;
+
+  for (i = 1; i < argc; i += n)
+    {
+      const char *opt = argv[i];
+
+      /* Interpret "-" or a non-switch as a file name.  */
+      if (opt[0] != '-' || opt[1] == '\0')
+       {
+         if (main_input_filename == NULL)
+           main_input_filename = opt;
+         add_input_filename (opt);
+         n = 1;
+         continue;
+       }
+
+      n = handle_option (argv + i, lang_mask);
+
+      if (!n)
+       {
+         n = 1;
+         error ("unrecognized command line option \"%s\"", opt);
+       }
+    }
+}
+
+/* Parse command line options and set default flag values.  Do minimal
+   options processing.  */
+void
+decode_options (unsigned int argc, const char **argv)
+{
+  unsigned int lang_mask;
+
+  /* Perform language-specific options initialization.  */
+  lang_mask = lang_hooks.init_options (argc, argv);
+
+  /* Scan to see what optimization level has been specified.  That will
+     determine the default value of many flags.  */
+
+  handle_options (argc, argv, lang_mask);
+}
+
+/* Handle target- and language-independent options.  Return zero to
+   generate an "unknown option" message.  Only options that need
+   extra handling need to be listed here; if you simply want
+   VALUE assigned to a variable, it happens automatically.  */
+
+static int
+common_handle_option (size_t scode, const char *arg,
+                     int value ATTRIBUTE_UNUSED)
+{
+  enum opt_code code = (enum opt_code) scode;
+
+  switch (code)
+    {
+    default:
+      abort ();
+
+    case OPT__help:
+      print_help ();
+      exit_after_options = true;
+      break;
+
+    case OPT__version:
+      print_version (stderr, "");
+      exit_after_options = true;
+      break;
+
+    case OPT_Werror:
+      warnings_are_errors = value;
+      break;
+
+    case OPT_Wsystem_headers:
+      warn_system_headers = value;
+      break;
+
+    case OPT_d:
+      decode_d_option (arg);
+      break;
+
+    case OPT_pedantic_errors:
+      flag_pedantic_errors = 1;
+      break;
+
+    case OPT_w:
+      inhibit_warnings = true;
+      break;
+    }
+
+  return 1;
+}
+
+/* Output --help text.  */
+static void
+print_help (void)
+{
+  size_t i;
+  const char *p;
+
+  GET_ENVIRONMENT (p, "COLUMNS");
+  if (p)
+    {
+      int value = atoi (p);
+      if (value > 0)
+       columns = value;
+    }
+
+  puts (_("The following options are language-independent:\n"));
+
+  print_filtered_help (CL_COMMON);
+
+  for (i = 0; lang_names[i]; i++)
+    {
+      printf (_("The %s front end recognizes the following options:\n\n"),
+             lang_names[i]);
+      print_filtered_help (1U << i);
+    }
+}
+
+/* Print help for a specific front-end, etc.  */
+static void
+print_filtered_help (unsigned int flag)
+{
+  unsigned int i, len, filter, indent = 0;
+  bool duplicates = false;
+  const char *help, *opt, *tab;
+  static char *printed;
+
+  if (flag == CL_COMMON || flag == CL_TARGET)
+    {
+      filter = flag;
+      if (!printed)
+       printed = xmalloc (cl_options_count);
+      memset (printed, 0, cl_options_count);
+    }
+  else
+    {
+      /* Don't print COMMON options twice.  */
+      filter = flag | CL_COMMON;
+
+      for (i = 0; i < cl_options_count; i++)
+       {
+         if ((cl_options[i].flags & filter) != flag)
+           continue;
+
+         /* Skip help for internal switches.  */
+         if (cl_options[i].flags & CL_UNDOCUMENTED)
+           continue;
+
+         /* Skip switches that have already been printed, mark them to be
+            listed later.  */
+         if (printed[i])
+           {
+             duplicates = true;
+             indent = print_switch (cl_options[i].opt_text, indent);
+           }
+       }
+
+      if (duplicates)
+       {
+         putchar ('\n');
+         putchar ('\n');
+       }
+    }
+
+  for (i = 0; i < cl_options_count; i++)
+    {
+      if ((cl_options[i].flags & filter) != flag)
+       continue;
+
+      /* Skip help for internal switches.  */
+      if (cl_options[i].flags & CL_UNDOCUMENTED)
+       continue;
+
+      /* Skip switches that have already been printed.  */
+      if (printed[i])
+       continue;
+
+      printed[i] = true;
+
+      help = cl_options[i].help;
+      if (!help)
+       help = undocumented_msg;
+
+      /* Get the translation.  */
+      help = _(help);
+
+      tab = strchr (help, '\t');
+      if (tab)
+       {
+         len = tab - help;
+         opt = help;
+         help = tab + 1;
+       }
+      else
+       {
+         opt = cl_options[i].opt_text;
+         len = strlen (opt);
+       }
+
+      wrap_help (help, opt, len);
+    }
+
+  putchar ('\n');
+}
+
+/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by
+   word-wrapped HELP in a second column.  */
+static unsigned int
+print_switch (const char *text, unsigned int indent)
+{
+  unsigned int len = strlen (text) + 1; /* trailing comma */
+
+  if (indent)
+    {
+      putchar (',');
+      if (indent + len > columns)
+       {
+         putchar ('\n');
+         putchar (' ');
+         indent = 1;
+       }
+    }
+  else
+    putchar (' ');
+
+  putchar (' ');
+  fputs (text, stdout);
+
+  return indent + len + 1;
+}
+
+/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by
+   word-wrapped HELP in a second column.  */
+static void
+wrap_help (const char *help, const char *item, unsigned int item_width)
+{
+  unsigned int col_width = 27;
+  unsigned int remaining, room, len;
+
+  remaining = strlen (help);
+
+  do
+    {
+      room = columns - 3 - MAX (col_width, item_width);
+      if (room > columns)
+       room = 0;
+      len = remaining;
+
+      if (room < len)
+       {
+         unsigned int i;
+
+         for (i = 0; help[i]; i++)
+           {
+             if (i >= room && len != remaining)
+               break;
+             if (help[i] == ' ')
+               len = i;
+             else if ((help[i] == '-' || help[i] == '/')
+                      && help[i + 1] != ' '
+                      && i > 0 && ISALPHA (help[i - 1]))
+               len = i + 1;
+           }
+       }
+
+      printf( "  %-*.*s %.*s\n", col_width, item_width, item, len, help);
+      item_width = 0;
+      while (help[len] == ' ')
+       len++;
+      help += len;
+      remaining -= len;
+    }
+  while (remaining);
+}
+
+/* Return 1 if OPTION is enabled, 0 if it is disabled, or -1 if it isn't
+   a simple on-off switch.  */
+
+int
+option_enabled (int opt_idx)
+{
+  const struct cl_option *option = &(cl_options[opt_idx]);
+  if (option->flag_var)
+    switch (option->var_type)
+      {
+      case CLVC_BOOLEAN:
+       return *(int *) option->flag_var != 0;
+
+      case CLVC_EQUAL:
+       return *(int *) option->flag_var == option->var_value;
+
+      case CLVC_BIT_CLEAR:
+       return (*(int *) option->flag_var & option->var_value) == 0;
+
+      case CLVC_BIT_SET:
+       return (*(int *) option->flag_var & option->var_value) != 0;
+
+      case CLVC_STRING:
+       break;
+      }
+  return -1;
+}
+
+/* Fill STATE with the current state of option OPTION.  Return true if
+   there is some state to store.  */
+
+bool
+get_option_state (int option, struct cl_option_state *state)
+{
+  if (cl_options[option].flag_var == 0)
+    return false;
+
+  switch (cl_options[option].var_type)
+    {
+    case CLVC_BOOLEAN:
+    case CLVC_EQUAL:
+      state->data = cl_options[option].flag_var;
+      state->size = sizeof (int);
+      break;
+
+    case CLVC_BIT_CLEAR:
+    case CLVC_BIT_SET:
+      state->ch = option_enabled (option);
+      state->data = &state->ch;
+      state->size = 1;
+      break;
+
+    case CLVC_STRING:
+      state->data = *(const char **) cl_options[option].flag_var;
+      if (state->data == 0)
+       state->data = "";
+      state->size = strlen (state->data) + 1;
+      break;
+    }
+  return true;
+}