]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/gcc.c
*** empty log message ***
[gcc.git] / gcc / gcc.c
index 433c67826de484675479b9406346ca138bee91c8..6a6449d679caa53361e8d0961440ab44bd0fdc37 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -34,20 +34,19 @@ compilation is specified by a string called a "spec".  */
 #include <sys/types.h>
 #include <ctype.h>
 #include <signal.h>
-#include <sys/file.h>
 #include <sys/stat.h>
 
 #include "config.h"
 #include "obstack.h"
 #include "gvarargs.h"
 
-#ifdef USG
 #ifndef R_OK
 #define R_OK 4
 #define W_OK 2
 #define X_OK 1
 #endif
 
+#ifdef USG
 #define vfork fork
 #endif /* USG */
 
@@ -71,11 +70,12 @@ compilation is specified by a string called a "spec".  */
 
 /* By default there is no special suffix for executables.  */
 #ifndef EXECUTABLE_SUFFIX
-#if __MSDOS__
-#define EXECUTABLE_SUFFIX ".exe"
-#else
 #define EXECUTABLE_SUFFIX ""
 #endif
+
+/* By default, colon separates directories in a path.  */
+#ifndef PATH_SEPARATOR
+#define PATH_SEPARATOR ':'
 #endif
 
 #define obstack_chunk_alloc xmalloc
@@ -124,6 +124,13 @@ static int cross_compile = 0;
 
 static struct obstack obstack;
 
+/* This is the obstack to build an environment variable to pass to
+   collect2 that describes all of the relevant switches of what to
+   pass the compiler in building the list of pointers to constructors
+   and destructors.  */
+
+static struct obstack collect_obstack;
+
 extern char *version_string;
 
 static void set_spec ();
@@ -230,13 +237,15 @@ or with constant text in a single argument.
  %{S*:X} substitutes X if one or more switches whose names with -S are
        specified to CC.  Note that the tail part of the -S option
        (i.e. the part matched by the `*') will be substituted for each
-       occurance of %* within X.
+       occurrence of %* within X.
  %{S:X} substitutes X, but only if the -S switch was given to CC.
  %{!S:X} substitutes X, but only if the -S switch was NOT given to CC.
  %{|S:X} like %{S:X}, but if no S switch, substitute `-'.
  %{|!S:X} like %{!S:X}, but if there is an S switch, substitute `-'.
  %{.S:X} substitutes X, but only if processing a file with suffix S.
  %{!.S:X} substitutes X, but only if NOT processing a file with suffix S.
+ %(Spec) processes a specification defined in a specs file as *Spec:
+ %[Spec] as above, but put __ around -D arguments
 
 The conditional text X in a %{S:X} or %{!S:X} construct may contain
 other nested % constructs or spaces, or even newlines.  They are
@@ -352,7 +361,7 @@ static char *switches_need_spaces = SWITCHES_NEED_SPACES;
 #ifndef WORD_SWITCH_TAKES_ARG
 #define WORD_SWITCH_TAKES_ARG(STR)                     \
  (!strcmp (STR, "Tdata") || !strcmp (STR, "include")   \
-  || !strcmp (STR, "imacros"))
+  || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info"))
 #endif
 \f
 /* Record the mapping from file suffixes for compilation specs.  */
@@ -386,7 +395,7 @@ static struct compiler default_compilers[] =
 {
   {".c", "@c"},
   {"@c",
-   "cpp -lang-c %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+   "cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
         -undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
@@ -399,13 +408,14 @@ static struct compiler default_compilers[] =
                   %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a}\
                   %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
                   %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
+                  %{aux-info*}\
                   %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
                   %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
               %{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
                      %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\
                       %{!pipe:%g.s} %A\n }}}}"},
   {"-",
-   "%{E:cpp -lang-c %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+   "%{E:cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
         -undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
@@ -417,7 +427,7 @@ static struct compiler default_compilers[] =
     %{!E:%e-E required when input is from standard input}"},
   {".m", "@objective-c"},
   {"@objective-c",
-   "cpp -lang-objc %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+   "cpp -lang-objc %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
         -undef -D__OBJC__ -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
@@ -431,6 +441,7 @@ static struct compiler default_compilers[] =
                   %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
                   %{traditional} %{v:-version} %{pg:-p} %{p} %{f*} \
                   -lang-objc %{gen-decls} \
+                  %{aux-info*}\
                   %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
                   %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
               %{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
@@ -439,7 +450,7 @@ static struct compiler default_compilers[] =
   {".h", "@c-header"},
   {"@c-header",
    "%{!E:%eCompilation of header file requested} \
-    cpp %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+    cpp %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
         %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} \
         -undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
@@ -452,7 +463,7 @@ static struct compiler default_compilers[] =
   {".cxx", "@c++"},
   {".C", "@c++"},
   {"@c++",
-   "cpp -lang-c++ %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+   "cpp -lang-c++ %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
        %{C:%{!E:%eGNU C++ does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} \
        -undef -D__GNUC__=2 -D__GNUG__=2 -D__cplusplus \
@@ -465,6 +476,7 @@ static struct compiler default_compilers[] =
                   %{!Q:-quiet} -dumpbase %b.cc %{d*} %{m*} %{a}\
                   %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} %{traditional}\
                   %{v:-version} %{pg:-p} %{p} %{f*}\
+                  %{aux-info*}\
                   %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
                   %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
               %{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
@@ -475,6 +487,7 @@ static struct compiler default_compilers[] =
    "cc1 %i %1 %{!Q:-quiet} %{d*} %{m*} %{a}\
        %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} %{traditional}\
        %{v:-version} %{pg:-p} %{p} %{f*}\
+       %{aux-info*}\
        %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
        %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
     %{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
@@ -484,6 +497,7 @@ static struct compiler default_compilers[] =
    "cc1plus %i %1 %2 %{!Q:-quiet} %{d*} %{m*} %{a}\
            %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} %{traditional}\
            %{v:-version} %{pg:-p} %{p} %{f*}\
+           %{aux-info*}\
            %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
            %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
        %{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
@@ -495,7 +509,7 @@ static struct compiler default_compilers[] =
             %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o} %i %A\n }"},
   {".S", "@assembler-with-cpp"},
   {"@assembler-with-cpp",
-   "cpp -lang-asm %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+   "cpp -lang-asm %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{trigraphs} \
         -undef -$ %{!undef:%p %P} -D__ASSEMBLER__ \
@@ -519,22 +533,23 @@ static int n_default_compilers
 
 #ifdef LINK_LIBGCC_SPECIAL
 /* Have gcc do the search.  */
+/* -u* was put back because both BSD and SysV seem to support it.  */
 static char *link_command_spec = "\
-%{!c:%{!M:%{!MM:%{!E:%{!S:ld %X %l %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
-                       %{r} %{s} %{T*} %{t} %{x} %{z}\
+%{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+                       %{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
                        %{!A:%{!nostdlib:%S}} \
                        %{L*} %D %o %{!nostdlib:libgcc.a%s %L libgcc.a%s %{!A:%E}}\n }}}}}";
 #else
 /* Use -l and have the linker do the search.  */
 static char *link_command_spec = "\
-%{!c:%{!M:%{!MM:%{!E:%{!S:ld %X %l %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
-                       %{r} %{T*} %{t} %{x} %{z}\
+%{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+                       %{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
                        %{!A:%{!nostdlib:%S}} \
                        %{L*} %D %o %{!nostdlib:-lgcc %L -lgcc %{!A:%E}}\n }}}}}";
 #endif
 
 /* A vector of options to give to the linker.
-   These options are accumlated by %x
+   These options are accumulated by %x
    and substituted into the linker command with %X.  */
 static int n_linker_options;
 static char **linker_options;
@@ -620,7 +635,6 @@ read_specs (filename)
          else if (in[0] == '#')
            {
              while (*in && *in != '\n') in++;
-             if (*in) in++;
            }
          else
            *out++ = *in++;
@@ -678,7 +692,7 @@ skip_whitespace (p)
 }
 \f
 /* Structure to keep track of the specs that have been defined so far.  These
-   are accessed using %Sspecname in a compiler or link spec. */
+   are accessed using %(specname) or %[specname] in a compiler or link spec. */
 
 struct spec_list
 {
@@ -1045,6 +1059,101 @@ choose_temp_base ()
   mktemp (temp_filename);
   temp_filename_length = strlen (temp_filename);
 }
+\f
+
+/* Routine to add variables to the environment.  We do this to pass
+   the pathname of the gcc driver, and the directories search to the
+   collect2 program, which is being run as ld.  This way, we can be
+   sure of executing the right compiler when collect2 wants to build
+   constructors and destructors.  Since the environment variables we
+   use come from an obstack, we don't have to worry about allocating
+   space for them.  */
+
+#ifndef HAVE_PUTENV
+
+putenv (str)
+     char *str;
+{
+#ifndef VMS                    /* nor about VMS */
+
+  extern char **environ;
+  char **old_environ = environ;
+  char **envp;
+  int num_envs = 0;
+  int name_len = 1;
+  int str_len = strlen (str);
+  char *p = str;
+  int ch;
+
+  while ((ch = *p++) != '\0' && ch != '=')
+    name_len++;
+
+  if (!ch)
+    abort ();
+
+  /* Search for replacing an existing environment variable, and
+     count the number of total environment variables.  */
+  for (envp = old_environ; *envp; envp++)
+    {
+      num_envs++;
+      if (!strncmp (str, *envp, name_len))
+       {
+         *envp = str;
+         return;
+       }
+    }
+
+  /* Add a new environment variable */
+  environ = (char **) xmalloc (sizeof (char *) * (num_envs+2));
+  *environ = str;
+  bcopy (old_environ, environ+1, sizeof (char *) * (num_envs+1));
+
+#endif /* VMS */
+}
+
+#endif /* HAVE_PUTENV */
+
+\f
+/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect.  */
+
+static void
+putenv_from_prefixes (paths, env_var)
+     struct path_prefix *paths;
+     char *env_var;
+{
+  int suffix_len = (machine_suffix) ? strlen (machine_suffix) : 0;
+  int first_time = TRUE;
+  struct prefix_list *pprefix;
+
+  obstack_grow (&collect_obstack, env_var, strlen (env_var));
+
+  for (pprefix = paths->plist; pprefix != 0; pprefix = pprefix->next)
+    {
+      int len = strlen (pprefix->prefix);
+
+      if (machine_suffix)
+       {
+         if (!first_time)
+           obstack_grow (&collect_obstack, ":", 1);
+           
+         first_time = FALSE;
+         obstack_grow (&collect_obstack, pprefix->prefix, len);
+         obstack_grow (&collect_obstack, machine_suffix, suffix_len);
+       }
+
+      if (!pprefix->require_machine_suffix)
+       {
+         if (!first_time)
+           obstack_grow (&collect_obstack, ":", 1);
+
+         first_time = FALSE;
+         obstack_grow (&collect_obstack, pprefix->prefix, len);
+       }
+    }
+  obstack_grow (&collect_obstack, "\0", 1);
+  putenv (obstack_finish (&collect_obstack));
+}
+
 \f
 /* Search for NAME using the prefix list PREFIXES.  MODE is passed to
    access to check permissions.
@@ -1261,19 +1370,28 @@ pexecute (func, program, argv, not_last)
   FILE *argfile;
   int i;
 
-  scmd = (char *)malloc(strlen(program) + strlen(temp_filename) + 6);
-  sprintf(scmd, "%s @%s.gp", program, temp_filename);
-  argfile = fopen(scmd+strlen(program)+2, "w");
+  scmd = (char *)malloc (strlen (program) + strlen (temp_filename) + 6);
+  sprintf (scmd, "%s @%s.gp", program, temp_filename);
+  argfile = fopen (scmd+strlen (program) + 2, "w");
   if (argfile == 0)
-    pfatal_with_name(scmd+strlen(program)+2);
+    pfatal_with_name (scmd + strlen (program) + 2);
 
   for (i=1; argv[i]; i++)
-    fprintf(argfile, "%s\n", argv[i]);
-  fclose(argfile);
+  {
+    char *cp;
+    for (cp = argv[i]; *cp; cp++)
+      {
+       if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
+         fputc ('\\', argfile);
+       fputc (*cp, argfile);
+      }
+    fputc ('\n', argfile);
+  }
+  fclose (argfile);
 
-  i = system(scmd);
+  i = system (scmd);
 
-  remove(scmd+strlen(program)+2);
+  remove (scmd + strlen (program) + 2);
   return i << 8;
 }
 
@@ -1427,7 +1545,7 @@ execute ()
 
   /* If -v, print what we are about to do, and maybe query.  */
 
-  if (verbose_flag || save_temps_flag)
+  if (verbose_flag)
     {
       /* Print each piped command as a separate line.  */
       for (i = 0; i < n_commands ; i++)
@@ -1584,7 +1702,7 @@ process_command (argc, argv)
       startp = endp = temp;
       while (1)
        {
-         if ((*endp == ':') || (*endp == 0))
+         if (*endp == PATH_SEPARATOR || *endp == 0)
            {
              strncpy (nstore, startp, endp-startp);
              if (endp == startp)
@@ -1617,7 +1735,7 @@ process_command (argc, argv)
       startp = endp = temp;
       while (1)
        {
-         if ((*endp == ':') || (*endp == 0))
+         if (*endp == PATH_SEPARATOR || *endp == 0)
            {
              strncpy (nstore, startp, endp-startp);
              if (endp == startp)
@@ -1653,7 +1771,7 @@ process_command (argc, argv)
       startp = endp = temp;
       while (1)
        {
-         if ((*endp == ':') || (*endp == 0))
+         if (*endp == PATH_SEPARATOR || *endp == 0)
            {
              strncpy (nstore, startp, endp-startp);
              if (endp == startp)
@@ -2100,6 +2218,10 @@ do_spec_1 (spec, inswitch, soft_matched_part)
              {
                struct prefix_list *pl
                  = (i == 0 ? library_prefix.plist : startfile_prefix.plist);
+               int bufsize = 100;
+               char *buffer = (char *) xmalloc (bufsize);
+               int idx;
+
                for (; pl; pl = pl->next)
                  {
 #ifdef RELATIVE_PREFIX_NOT_LINKDIR
@@ -2120,7 +2242,15 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                            do_spec_1 (" ", 0, 0);
 #endif
                            do_spec_1 (pl->prefix, 1, 0);
-                           do_spec_1 (machine_suffix, 1, 0);
+                           /* Remove slash from machine_suffix.  */
+                           if (strlen (machine_suffix) >= bufsize)
+                             bufsize = strlen (machine_suffix) * 2 + 1;
+                           buffer = (char *) xrealloc (buffer, bufsize);
+                           strcpy (buffer, machine_suffix);
+                           idx = strlen (buffer);
+                           if (buffer[idx - 1] == '/')
+                             buffer[idx - 1] = 0;
+                           do_spec_1 (buffer, 1, 0);
                            /* Make this a separate argument.  */
                            do_spec_1 (" ", 0, 0);
                          }
@@ -2133,12 +2263,21 @@ do_spec_1 (spec, inswitch, soft_matched_part)
 #ifdef SPACE_AFTER_L_OPTION
                            do_spec_1 (" ", 0, 0);
 #endif
-                           do_spec_1 (pl->prefix, 1, 0);
+                           /* Remove slash from pl->prefix.  */
+                           if (strlen (pl->prefix) >= bufsize)
+                             bufsize = strlen (pl->prefix) * 2 + 1;
+                           buffer = (char *) xrealloc (buffer, bufsize);
+                           strcpy (buffer, pl->prefix);
+                           idx = strlen (buffer);
+                           if (buffer[idx - 1] == '/')
+                             buffer[idx - 1] = 0;
+                           do_spec_1 (buffer, 1, 0);
                            /* Make this a separate argument.  */
                            do_spec_1 (" ", 0, 0);
                          }
                      }
                  }
+               free (buffer);
              }
            break;
 
@@ -2508,6 +2647,10 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                      do_spec_1 (buf, 0, NULL);
                    }
                }
+
+             /* Discard the closing paren or bracket.  */
+             if (*p)
+               p++;
            }
            break;
 
@@ -2622,7 +2765,7 @@ handle_braces (p)
 
          /* First see whether we have %*.  */
          substitution = 0;
-         while (*r && *r == '}')
+         while (r < q)
            {
              if (*r == '%' && r[1] == '*')
                substitution = 1;
@@ -2828,6 +2971,13 @@ main (argc, argv)
 
   obstack_init (&obstack);
 
+  /* Set up to remember the pathname of gcc and any options
+     needed for collect.  */
+  obstack_init (&collect_obstack);
+  obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=")-1);
+  obstack_grow (&collect_obstack, programname, strlen (programname)+1);
+  putenv (obstack_finish (&collect_obstack));
+
   /* Choose directory for temp files.  */
 
   choose_temp_base ();
@@ -2983,6 +3133,40 @@ main (argc, argv)
   if (error_count == 0)
     {
       int tmp = execution_count;
+      int i;
+      int first_time;
+
+      /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
+        for collect.  */
+      putenv_from_prefixes (&exec_prefix, "COMPILER_PATH=");
+      putenv_from_prefixes (&startfile_prefix, "LIBRARY_PATH=");
+
+      /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
+        the compiler.  */
+      obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
+                   sizeof ("COLLECT_GCC_OPTIONS=")-1);
+
+      first_time = TRUE;
+      for (i = 0; i < n_switches; i++)
+       {
+         char **args;
+         if (!first_time)
+           obstack_grow (&collect_obstack, " ", 1);
+
+         first_time = FALSE;
+         obstack_grow (&collect_obstack, "-", 1);
+         obstack_grow (&collect_obstack, switches[i].part1,
+                       strlen (switches[i].part1));
+
+         for (args = switches[i].args; args && *args; args++)
+           {
+             obstack_grow (&collect_obstack, " ", 1);
+             obstack_grow (&collect_obstack, *args, strlen (*args));
+           }
+       }
+      obstack_grow (&collect_obstack, "\0", 1);
+      putenv (obstack_finish (&collect_obstack));
+
       value = do_spec (link_command_spec);
       if (value < 0)
        error_count = 1;
@@ -3236,6 +3420,7 @@ validate_all_switches ()
   struct compiler *comp;
   register char *p;
   register char c;
+  struct spec_list *spec;
 
   for (comp = compilers; comp->spec; comp++)
     {
@@ -3246,6 +3431,16 @@ validate_all_switches ()
          validate_switches (p + 1);
     }
 
+  /* look through the linked list of extra specs read from the specs file */
+  for (spec = specs ; spec ; spec = spec->next)
+    {
+      p = spec->spec;
+      while (c = *p++)
+       if (c == '%' && *p == '{')
+         /* We have a switch spec.  */
+         validate_switches (p + 1);
+    }
+
   p = link_command_spec;
   while (c = *p++)
     if (c == '%' && *p == '{')
This page took 0.043977 seconds and 5 git commands to generate.