Blame gettext-runtime/src/envsubst.c

Packit 5b56b6
/* Substitution of environment variables in shell format strings.
Packit 5b56b6
   Copyright (C) 2003-2007, 2012, 2015 Free Software Foundation, Inc.
Packit 5b56b6
   Written by Bruno Haible <bruno@clisp.org>, 2003.
Packit 5b56b6
Packit 5b56b6
   This program is free software: you can redistribute it and/or modify
Packit 5b56b6
   it under the terms of the GNU General Public License as published by
Packit 5b56b6
   the Free Software Foundation; either version 3 of the License, or
Packit 5b56b6
   (at your option) any later version.
Packit 5b56b6
Packit 5b56b6
   This program is distributed in the hope that it will be useful,
Packit 5b56b6
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5b56b6
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 5b56b6
   GNU General Public License for more details.
Packit 5b56b6
Packit 5b56b6
   You should have received a copy of the GNU General Public License
Packit 5b56b6
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 5b56b6
Packit 5b56b6
#ifdef HAVE_CONFIG_H
Packit 5b56b6
# include <config.h>
Packit 5b56b6
#endif
Packit 5b56b6
Packit 5b56b6
#include <errno.h>
Packit 5b56b6
#include <getopt.h>
Packit 5b56b6
#include <stdbool.h>
Packit 5b56b6
#include <stdio.h>
Packit 5b56b6
#include <stdlib.h>
Packit 5b56b6
#include <string.h>
Packit 5b56b6
#include <locale.h>
Packit 5b56b6
Packit 5b56b6
#include "closeout.h"
Packit 5b56b6
#include "error.h"
Packit 5b56b6
#include "progname.h"
Packit 5b56b6
#include "relocatable.h"
Packit 5b56b6
#include "basename.h"
Packit 5b56b6
#include "xalloc.h"
Packit 5b56b6
#include "propername.h"
Packit 5b56b6
#include "gettext.h"
Packit 5b56b6
Packit 5b56b6
#define _(str) gettext (str)
Packit 5b56b6
Packit 5b56b6
/* If true, substitution shall be performed on all variables.  */
Packit 5b56b6
static bool all_variables;
Packit 5b56b6
Packit 5b56b6
/* Long options.  */
Packit 5b56b6
static const struct option long_options[] =
Packit 5b56b6
{
Packit 5b56b6
  { "help", no_argument, NULL, 'h' },
Packit 5b56b6
  { "variables", no_argument, NULL, 'v' },
Packit 5b56b6
  { "version", no_argument, NULL, 'V' },
Packit 5b56b6
  { NULL, 0, NULL, 0 }
Packit 5b56b6
};
Packit 5b56b6
Packit 5b56b6
/* Forward declaration of local functions.  */
Packit 5b56b6
static void usage (int status)
Packit 5b56b6
#if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
Packit 5b56b6
     __attribute__ ((noreturn))
Packit 5b56b6
#endif
Packit 5b56b6
;
Packit 5b56b6
static void print_variables (const char *string);
Packit 5b56b6
static void note_variables (const char *string);
Packit 5b56b6
static void subst_from_stdin (void);
Packit 5b56b6
Packit 5b56b6
int
Packit 5b56b6
main (int argc, char *argv[])
Packit 5b56b6
{
Packit 5b56b6
  /* Default values for command line options.  */
Packit 5b56b6
  bool show_variables = false;
Packit 5b56b6
  bool do_help = false;
Packit 5b56b6
  bool do_version = false;
Packit 5b56b6
Packit 5b56b6
  int opt;
Packit 5b56b6
Packit 5b56b6
  /* Set program name for message texts.  */
Packit 5b56b6
  set_program_name (argv[0]);
Packit 5b56b6
Packit 5b56b6
#ifdef HAVE_SETLOCALE
Packit 5b56b6
  /* Set locale via LC_ALL.  */
Packit 5b56b6
  setlocale (LC_ALL, "");
Packit 5b56b6
#endif
Packit 5b56b6
Packit 5b56b6
  /* Set the text message domain.  */
Packit 5b56b6
  bindtextdomain (PACKAGE, relocate (LOCALEDIR));
Packit 5b56b6
  textdomain (PACKAGE);
Packit 5b56b6
Packit 5b56b6
  /* Ensure that write errors on stdout are detected.  */
Packit 5b56b6
  atexit (close_stdout);
Packit 5b56b6
Packit 5b56b6
  /* Parse command line options.  */
Packit 5b56b6
  while ((opt = getopt_long (argc, argv, "hvV", long_options, NULL)) != EOF)
Packit 5b56b6
    switch (opt)
Packit 5b56b6
    {
Packit 5b56b6
    case '\0':          /* Long option.  */
Packit 5b56b6
      break;
Packit 5b56b6
    case 'h':
Packit 5b56b6
      do_help = true;
Packit 5b56b6
      break;
Packit 5b56b6
    case 'v':
Packit 5b56b6
      show_variables = true;
Packit 5b56b6
      break;
Packit 5b56b6
    case 'V':
Packit 5b56b6
      do_version = true;
Packit 5b56b6
      break;
Packit 5b56b6
    default:
Packit 5b56b6
      usage (EXIT_FAILURE);
Packit 5b56b6
    }
Packit 5b56b6
Packit 5b56b6
  /* Version information is requested.  */
Packit 5b56b6
  if (do_version)
Packit 5b56b6
    {
Packit 5b56b6
      printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
Packit 5b56b6
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
Packit 5b56b6
This is free software: you are free to change and redistribute it.\n\
Packit 5b56b6
There is NO WARRANTY, to the extent permitted by law.\n\
Packit 5b56b6
"),
Packit 5b56b6
              "2003-2007");
Packit 5b56b6
      printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
Packit 5b56b6
      exit (EXIT_SUCCESS);
Packit 5b56b6
    }
Packit 5b56b6
Packit 5b56b6
  /* Help is requested.  */
Packit 5b56b6
  if (do_help)
Packit 5b56b6
    usage (EXIT_SUCCESS);
Packit 5b56b6
Packit 5b56b6
  if (argc - optind > 1)
Packit 5b56b6
    error (EXIT_FAILURE, 0, _("too many arguments"));
Packit 5b56b6
Packit 5b56b6
  /* Distinguish the two main operation modes.  */
Packit 5b56b6
  if (show_variables)
Packit 5b56b6
    {
Packit 5b56b6
      /* Output only the variables.  */
Packit 5b56b6
      switch (argc - optind)
Packit 5b56b6
        {
Packit 5b56b6
        case 1:
Packit 5b56b6
          break;
Packit 5b56b6
        case 0:
Packit 5b56b6
          error (EXIT_FAILURE, 0, _("missing arguments"));
Packit 5b56b6
        default:
Packit 5b56b6
          abort ();
Packit 5b56b6
        }
Packit 5b56b6
      print_variables (argv[optind++]);
Packit 5b56b6
    }
Packit 5b56b6
  else
Packit 5b56b6
    {
Packit 5b56b6
      /* Actually perform the substitutions.  */
Packit 5b56b6
      switch (argc - optind)
Packit 5b56b6
        {
Packit 5b56b6
        case 1:
Packit 5b56b6
          all_variables = false;
Packit 5b56b6
          note_variables (argv[optind++]);
Packit 5b56b6
          break;
Packit 5b56b6
        case 0:
Packit 5b56b6
          all_variables = true;
Packit 5b56b6
          break;
Packit 5b56b6
        default:
Packit 5b56b6
          abort ();
Packit 5b56b6
        }
Packit 5b56b6
      subst_from_stdin ();
Packit 5b56b6
    }
Packit 5b56b6
Packit 5b56b6
  exit (EXIT_SUCCESS);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
Packit 5b56b6
/* Display usage information and exit.  */
Packit 5b56b6
static void
Packit 5b56b6
usage (int status)
Packit 5b56b6
{
Packit 5b56b6
  if (status != EXIT_SUCCESS)
Packit 5b56b6
    fprintf (stderr, _("Try '%s --help' for more information.\n"),
Packit 5b56b6
             program_name);
Packit 5b56b6
  else
Packit 5b56b6
    {
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("\
Packit 5b56b6
Usage: %s [OPTION] [SHELL-FORMAT]\n\
Packit 5b56b6
"), program_name);
Packit 5b56b6
      printf ("\n");
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("\
Packit 5b56b6
Substitutes the values of environment variables.\n"));
Packit 5b56b6
      printf ("\n");
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("\
Packit 5b56b6
Operation mode:\n"));
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("\
Packit 5b56b6
  -v, --variables             output the variables occurring in SHELL-FORMAT\n"));
Packit 5b56b6
      printf ("\n");
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("\
Packit 5b56b6
Informative output:\n"));
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("\
Packit 5b56b6
  -h, --help                  display this help and exit\n"));
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("\
Packit 5b56b6
  -V, --version               output version information and exit\n"));
Packit 5b56b6
      printf ("\n");
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("\
Packit 5b56b6
In normal operation mode, standard input is copied to standard output,\n\
Packit 5b56b6
with references to environment variables of the form $VARIABLE or ${VARIABLE}\n\
Packit 5b56b6
being replaced with the corresponding values.  If a SHELL-FORMAT is given,\n\
Packit 5b56b6
only those environment variables that are referenced in SHELL-FORMAT are\n\
Packit 5b56b6
substituted; otherwise all environment variables references occurring in\n\
Packit 5b56b6
standard input are substituted.\n"));
Packit 5b56b6
      printf ("\n");
Packit 5b56b6
      /* xgettext: no-wrap */
Packit 5b56b6
      printf (_("\
Packit 5b56b6
When --variables is used, standard input is ignored, and the output consists\n\
Packit 5b56b6
of the environment variables that are referenced in SHELL-FORMAT, one per line.\n"));
Packit 5b56b6
      printf ("\n");
Packit 5b56b6
      /* TRANSLATORS: The placeholder indicates the bug-reporting address
Packit 5b56b6
         for this package.  Please add _another line_ saying
Packit 5b56b6
         "Report translation bugs to <...>\n" with the address for translation
Packit 5b56b6
         bugs (typically your translation team's web or email address).  */
Packit 5b56b6
      fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"), stdout);
Packit 5b56b6
    }
Packit 5b56b6
Packit 5b56b6
  exit (status);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
Packit 5b56b6
/* Parse the string and invoke the callback each time a $VARIABLE or
Packit 5b56b6
   ${VARIABLE} construct is seen, where VARIABLE is a nonempty sequence
Packit 5b56b6
   of ASCII alphanumeric/underscore characters, starting with an ASCII
Packit 5b56b6
   alphabetic/underscore character.
Packit 5b56b6
   We allow only ASCII characters, to avoid dependencies w.r.t. the current
Packit 5b56b6
   encoding: While "${\xe0}" looks like a variable access in ISO-8859-1
Packit 5b56b6
   encoding, it doesn't look like one in the BIG5, BIG5-HKSCS, GBK, GB18030,
Packit 5b56b6
   SHIFT_JIS, JOHAB encodings, because \xe0\x7d is a single character in these
Packit 5b56b6
   encodings.  */
Packit 5b56b6
static void
Packit 5b56b6
find_variables (const char *string,
Packit 5b56b6
                void (*callback) (const char *var_ptr, size_t var_len))
Packit 5b56b6
{
Packit 5b56b6
  for (; *string != '\0';)
Packit 5b56b6
    if (*string++ == '$')
Packit 5b56b6
      {
Packit 5b56b6
        const char *variable_start;
Packit 5b56b6
        const char *variable_end;
Packit 5b56b6
        bool valid;
Packit 5b56b6
        char c;
Packit 5b56b6
Packit 5b56b6
        if (*string == '{')
Packit 5b56b6
          string++;
Packit 5b56b6
Packit 5b56b6
        variable_start = string;
Packit 5b56b6
        c = *string;
Packit 5b56b6
        if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
Packit 5b56b6
          {
Packit 5b56b6
            do
Packit 5b56b6
              c = *++string;
Packit 5b56b6
            while ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
Packit 5b56b6
                   || (c >= '0' && c <= '9') || c == '_');
Packit 5b56b6
            variable_end = string;
Packit 5b56b6
Packit 5b56b6
            if (variable_start[-1] == '{')
Packit 5b56b6
              {
Packit 5b56b6
                if (*string == '}')
Packit 5b56b6
                  {
Packit 5b56b6
                    string++;
Packit 5b56b6
                    valid = true;
Packit 5b56b6
                  }
Packit 5b56b6
                else
Packit 5b56b6
                  valid = false;
Packit 5b56b6
              }
Packit 5b56b6
            else
Packit 5b56b6
              valid = true;
Packit 5b56b6
Packit 5b56b6
            if (valid)
Packit 5b56b6
              callback (variable_start, variable_end - variable_start);
Packit 5b56b6
          }
Packit 5b56b6
      }
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
Packit 5b56b6
/* Print a variable to stdout, followed by a newline.  */
Packit 5b56b6
static void
Packit 5b56b6
print_variable (const char *var_ptr, size_t var_len)
Packit 5b56b6
{
Packit 5b56b6
  fwrite (var_ptr, var_len, 1, stdout);
Packit 5b56b6
  putchar ('\n');
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Print the variables contained in STRING to stdout, each one followed by a
Packit 5b56b6
   newline.  */
Packit 5b56b6
static void
Packit 5b56b6
print_variables (const char *string)
Packit 5b56b6
{
Packit 5b56b6
  find_variables (string, &print_variable);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
Packit 5b56b6
/* Type describing list of immutable strings,
Packit 5b56b6
   implemented using a dynamic array.  */
Packit 5b56b6
typedef struct string_list_ty string_list_ty;
Packit 5b56b6
struct string_list_ty
Packit 5b56b6
{
Packit 5b56b6
  const char **item;
Packit 5b56b6
  size_t nitems;
Packit 5b56b6
  size_t nitems_max;
Packit 5b56b6
};
Packit 5b56b6
Packit 5b56b6
/* Initialize an empty list of strings.  */
Packit 5b56b6
static inline void
Packit 5b56b6
string_list_init (string_list_ty *slp)
Packit 5b56b6
{
Packit 5b56b6
  slp->item = NULL;
Packit 5b56b6
  slp->nitems = 0;
Packit 5b56b6
  slp->nitems_max = 0;
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Append a single string to the end of a list of strings.  */
Packit 5b56b6
static inline void
Packit 5b56b6
string_list_append (string_list_ty *slp, const char *s)
Packit 5b56b6
{
Packit 5b56b6
  /* Grow the list.  */
Packit 5b56b6
  if (slp->nitems >= slp->nitems_max)
Packit 5b56b6
    {
Packit 5b56b6
      size_t nbytes;
Packit 5b56b6
Packit 5b56b6
      slp->nitems_max = slp->nitems_max * 2 + 4;
Packit 5b56b6
      nbytes = slp->nitems_max * sizeof (slp->item[0]);
Packit 5b56b6
      slp->item = (const char **) xrealloc (slp->item, nbytes);
Packit 5b56b6
    }
Packit 5b56b6
Packit 5b56b6
  /* Add the string to the end of the list.  */
Packit 5b56b6
  slp->item[slp->nitems++] = s;
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Compare two strings given by reference.  */
Packit 5b56b6
static int
Packit 5b56b6
cmp_string (const void *pstr1, const void *pstr2)
Packit 5b56b6
{
Packit 5b56b6
  const char *str1 = *(const char **)pstr1;
Packit 5b56b6
  const char *str2 = *(const char **)pstr2;
Packit 5b56b6
Packit 5b56b6
  return strcmp (str1, str2);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Sort a list of strings.  */
Packit 5b56b6
static inline void
Packit 5b56b6
string_list_sort (string_list_ty *slp)
Packit 5b56b6
{
Packit 5b56b6
  if (slp->nitems > 0)
Packit 5b56b6
    qsort (slp->item, slp->nitems, sizeof (slp->item[0]), cmp_string);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Test whether a string list contains a given string.  */
Packit 5b56b6
static inline int
Packit 5b56b6
string_list_member (const string_list_ty *slp, const char *s)
Packit 5b56b6
{
Packit 5b56b6
  size_t j;
Packit 5b56b6
Packit 5b56b6
  for (j = 0; j < slp->nitems; ++j)
Packit 5b56b6
    if (strcmp (slp->item[j], s) == 0)
Packit 5b56b6
      return 1;
Packit 5b56b6
  return 0;
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Test whether a sorted string list contains a given string.  */
Packit 5b56b6
static int
Packit 5b56b6
sorted_string_list_member (const string_list_ty *slp, const char *s)
Packit 5b56b6
{
Packit 5b56b6
  size_t j1, j2;
Packit 5b56b6
Packit 5b56b6
  j1 = 0;
Packit 5b56b6
  j2 = slp->nitems;
Packit 5b56b6
  if (j2 > 0)
Packit 5b56b6
    {
Packit 5b56b6
      /* Binary search.  */
Packit 5b56b6
      while (j2 - j1 > 1)
Packit 5b56b6
        {
Packit 5b56b6
          /* Here we know that if s is in the list, it is at an index j
Packit 5b56b6
             with j1 <= j < j2.  */
Packit 5b56b6
          size_t j = (j1 + j2) >> 1;
Packit 5b56b6
          int result = strcmp (slp->item[j], s);
Packit 5b56b6
Packit 5b56b6
          if (result > 0)
Packit 5b56b6
            j2 = j;
Packit 5b56b6
          else if (result == 0)
Packit 5b56b6
            return 1;
Packit 5b56b6
          else
Packit 5b56b6
            j1 = j + 1;
Packit 5b56b6
        }
Packit 5b56b6
      if (j2 > j1)
Packit 5b56b6
        if (strcmp (slp->item[j1], s) == 0)
Packit 5b56b6
          return 1;
Packit 5b56b6
    }
Packit 5b56b6
  return 0;
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Destroy a list of strings.  */
Packit 5b56b6
static inline void
Packit 5b56b6
string_list_destroy (string_list_ty *slp)
Packit 5b56b6
{
Packit 5b56b6
  size_t j;
Packit 5b56b6
Packit 5b56b6
  for (j = 0; j < slp->nitems; ++j)
Packit 5b56b6
    free ((char *) slp->item[j]);
Packit 5b56b6
  if (slp->item != NULL)
Packit 5b56b6
    free (slp->item);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
Packit 5b56b6
/* Set of variables on which to perform substitution.
Packit 5b56b6
   Used only if !all_variables.  */
Packit 5b56b6
static string_list_ty variables_set;
Packit 5b56b6
Packit 5b56b6
/* Adds a variable to variables_set.  */
Packit 5b56b6
static void
Packit 5b56b6
note_variable (const char *var_ptr, size_t var_len)
Packit 5b56b6
{
Packit 5b56b6
  char *string = XNMALLOC (var_len + 1, char);
Packit 5b56b6
  memcpy (string, var_ptr, var_len);
Packit 5b56b6
  string[var_len] = '\0';
Packit 5b56b6
Packit 5b56b6
  string_list_append (&variables_set, string);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Stores the variables occurring in the string in variables_set.  */
Packit 5b56b6
static void
Packit 5b56b6
note_variables (const char *string)
Packit 5b56b6
{
Packit 5b56b6
  string_list_init (&variables_set);
Packit 5b56b6
  find_variables (string, &note_variable);
Packit 5b56b6
  string_list_sort (&variables_set);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
Packit 5b56b6
static int
Packit 5b56b6
do_getc ()
Packit 5b56b6
{
Packit 5b56b6
  int c = getc (stdin);
Packit 5b56b6
Packit 5b56b6
  if (c == EOF)
Packit 5b56b6
    {
Packit 5b56b6
      if (ferror (stdin))
Packit 5b56b6
        error (EXIT_FAILURE, errno, _("\
Packit 5b56b6
error while reading \"%s\""), _("standard input"));
Packit 5b56b6
    }
Packit 5b56b6
Packit 5b56b6
  return c;
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
static inline void
Packit 5b56b6
do_ungetc (int c)
Packit 5b56b6
{
Packit 5b56b6
  if (c != EOF)
Packit 5b56b6
    ungetc (c, stdin);
Packit 5b56b6
}
Packit 5b56b6
Packit 5b56b6
/* Copies stdin to stdout, performing substitutions.  */
Packit 5b56b6
static void
Packit 5b56b6
subst_from_stdin ()
Packit 5b56b6
{
Packit 5b56b6
  static char *buffer;
Packit 5b56b6
  static size_t bufmax;
Packit 5b56b6
  static size_t buflen;
Packit 5b56b6
  int c;
Packit 5b56b6
Packit 5b56b6
  for (;;)
Packit 5b56b6
    {
Packit 5b56b6
      c = do_getc ();
Packit 5b56b6
      if (c == EOF)
Packit 5b56b6
        break;
Packit 5b56b6
      /* Look for $VARIABLE or ${VARIABLE}.  */
Packit 5b56b6
      if (c == '$')
Packit 5b56b6
        {
Packit 5b56b6
          bool opening_brace = false;
Packit 5b56b6
          bool closing_brace = false;
Packit 5b56b6
Packit 5b56b6
          c = do_getc ();
Packit 5b56b6
          if (c == '{')
Packit 5b56b6
            {
Packit 5b56b6
              opening_brace = true;
Packit 5b56b6
              c = do_getc ();
Packit 5b56b6
            }
Packit 5b56b6
          if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
Packit 5b56b6
            {
Packit 5b56b6
              bool valid;
Packit 5b56b6
Packit 5b56b6
              /* Accumulate the VARIABLE in buffer.  */
Packit 5b56b6
              buflen = 0;
Packit 5b56b6
              do
Packit 5b56b6
                {
Packit 5b56b6
                  if (buflen >= bufmax)
Packit 5b56b6
                    {
Packit 5b56b6
                      bufmax = 2 * bufmax + 10;
Packit 5b56b6
                      buffer = xrealloc (buffer, bufmax);
Packit 5b56b6
                    }
Packit 5b56b6
                  buffer[buflen++] = c;
Packit 5b56b6
Packit 5b56b6
                  c = do_getc ();
Packit 5b56b6
                }
Packit 5b56b6
              while ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
Packit 5b56b6
                     || (c >= '0' && c <= '9') || c == '_');
Packit 5b56b6
Packit 5b56b6
              if (opening_brace)
Packit 5b56b6
                {
Packit 5b56b6
                  if (c == '}')
Packit 5b56b6
                    {
Packit 5b56b6
                      closing_brace = true;
Packit 5b56b6
                      valid = true;
Packit 5b56b6
                    }
Packit 5b56b6
                  else
Packit 5b56b6
                    {
Packit 5b56b6
                      valid = false;
Packit 5b56b6
                      do_ungetc (c);
Packit 5b56b6
                    }
Packit 5b56b6
                }
Packit 5b56b6
              else
Packit 5b56b6
                {
Packit 5b56b6
                  valid = true;
Packit 5b56b6
                  do_ungetc (c);
Packit 5b56b6
                }
Packit 5b56b6
Packit 5b56b6
              if (valid)
Packit 5b56b6
                {
Packit 5b56b6
                  /* Terminate the variable in the buffer.  */
Packit 5b56b6
                  if (buflen >= bufmax)
Packit 5b56b6
                    {
Packit 5b56b6
                      bufmax = 2 * bufmax + 10;
Packit 5b56b6
                      buffer = xrealloc (buffer, bufmax);
Packit 5b56b6
                    }
Packit 5b56b6
                  buffer[buflen] = '\0';
Packit 5b56b6
Packit 5b56b6
                  /* Test whether the variable shall be substituted.  */
Packit 5b56b6
                  if (!all_variables
Packit 5b56b6
                      && !sorted_string_list_member (&variables_set, buffer))
Packit 5b56b6
                    valid = false;
Packit 5b56b6
                }
Packit 5b56b6
Packit 5b56b6
              if (valid)
Packit 5b56b6
                {
Packit 5b56b6
                  /* Substitute the variable's value from the environment.  */
Packit 5b56b6
                  const char *env_value = getenv (buffer);
Packit 5b56b6
Packit 5b56b6
                  if (env_value != NULL)
Packit 5b56b6
                    fputs (env_value, stdout);
Packit 5b56b6
                }
Packit 5b56b6
              else
Packit 5b56b6
                {
Packit 5b56b6
                  /* Perform no substitution at all.  Since the buffered input
Packit 5b56b6
                     contains no other '$' than at the start, we can just
Packit 5b56b6
                     output all the buffered contents.  */
Packit 5b56b6
                  putchar ('$');
Packit 5b56b6
                  if (opening_brace)
Packit 5b56b6
                    putchar ('{');
Packit 5b56b6
                  fwrite (buffer, buflen, 1, stdout);
Packit 5b56b6
                  if (closing_brace)
Packit 5b56b6
                    putchar ('}');
Packit 5b56b6
                }
Packit 5b56b6
            }
Packit 5b56b6
          else
Packit 5b56b6
            {
Packit 5b56b6
              do_ungetc (c);
Packit 5b56b6
              putchar ('$');
Packit 5b56b6
              if (opening_brace)
Packit 5b56b6
                putchar ('{');
Packit 5b56b6
            }
Packit 5b56b6
        }
Packit 5b56b6
      else
Packit 5b56b6
        putchar (c);
Packit 5b56b6
    }
Packit 5b56b6
}