Logo Search packages:      
Sourcecode: yafc version File versions  Download package

bashline.c

/* bashline.c -- Bash's interface to the readline library. */

/* modified for use in Yafc by Martin Hedenfalk <mhe@home.se>
 * this is not the complete bashline.c, see the bash source,
 * available at ftp://ftp.gnu.org/pub/
 * 
 * latest modified 1999-07-22, 2000-11-04
 */

/* Copyright (C) 1987,1991 Free Software Foundation, Inc.

   This file is part of GNU Bash, the Bourne Again SHell.

   Bash 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 1, or (at your option)
   any later version.

   Bash 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 Bash; see the file COPYING.  If not, write to the Free
   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "syshdr.h"
#include "gvars.h"
#include "bashline.h"
#include "strq.h"  /* for tilde_expand_home */

#define COMPLETE_DQUOTE  1
#define COMPLETE_SQUOTE  2
#define COMPLETE_BSQUOTE 3

#ifdef HAVE_LIBREADLINE
static int completion_quoting_style = COMPLETE_BSQUOTE;
#endif

/* A function to strip quotes that are not protected by backquotes.  It
   allows single quotes to appear within double quotes, and vice versa.
   It should be smarter. */
char *bash_dequote_filename (const char *text, int quote_char)
{
      char *ret, *r;
      const char *p;
      int l, quoted;

  l = strlen (text);
  ret = xmalloc (l + 1);
  for (quoted = quote_char, p = text, r = ret; p && *p; p++)
    {
      /* Allow backslash-quoted characters to pass through unscathed. */
      if (*p == '\\')
      {
        *r++ = *++p;
        if (*p == '\0')
          break;
        continue;
      }
      /* Close quote. */
      if (quoted && *p == quoted)
        {
          quoted = 0;
          continue;
        }
      /* Open quote. */
      if (quoted == 0 && (*p == '\'' || *p == '"'))
        {
          quoted = *p;
          continue;
        }
      *r++ = *p;
    }
  *r = '\0';
  return ret;
}

/* these should really be defined in readline/readline.h */
#ifndef SINGLE_MATCH
# define SINGLE_MATCH 1
#endif
#ifndef MULT_MATCH
# define MULT_MATCH 2
#endif

#ifdef HAVE_LIBREADLINE
/* Quote a filename using double quotes, single quotes, or backslashes
   depending on the value of completion_quoting_style.  If we're
   completing using backslashes, we need to quote some additional
   characters (those that readline treats as word breaks), so we call
   quote_word_break_chars on the result. */
char *bash_quote_filename (char *s, int rtype, char *qcp)
{
  char *rtext, *mtext, *ret;
  int rlen, cs;

  rtext = (char *)NULL;

  /* If RTYPE == MULT_MATCH, it means that there is
     more than one match.  In this case, we do not add
     the closing quote or attempt to perform tilde
     expansion.  If RTYPE == SINGLE_MATCH, we try
     to perform tilde expansion, because single and double
     quotes inhibit tilde expansion by the shell. */

  mtext = s;
  if (mtext[0] == '~' && rtype == SINGLE_MATCH)
    mtext = tilde_expand_home (s, gvLocalHomeDir);

  cs = completion_quoting_style;
  /* Might need to modify the default completion style based on *qcp,
     since it's set to any user-provided opening quote. */
  if (*qcp == '"')
    cs = COMPLETE_DQUOTE;
  else if (*qcp == '\'')
    cs = COMPLETE_SQUOTE;
#if defined (BANG_HISTORY)
  else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE &&
         history_expansion_inhibited == 0 && strchr (mtext, '!'))
    cs = COMPLETE_BSQUOTE;

  if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE &&
        history_expansion_inhibited == 0 && strchr (mtext, '!'))
    {
      cs = COMPLETE_BSQUOTE;
      *qcp = '\0';
    }
#endif

  switch (cs)
    {
    case COMPLETE_DQUOTE:
      rtext = bash_double_quote (mtext);
      break;
    case COMPLETE_SQUOTE:
      rtext = bash_single_quote (mtext);
      break;
    case COMPLETE_BSQUOTE:
      rtext = bash_backslash_quote (mtext);
      break;
    }

  if (mtext != s)
    free (mtext);

  /* We may need to quote additional characters: those that readline treats
     as word breaks that are not quoted by backslash_quote. */
  if (rtext && cs == COMPLETE_BSQUOTE)
    {
      mtext = quote_word_break_chars (rtext);
      free (rtext);
      rtext = mtext;
    }

  /* Leave the opening quote intact.  The readline completion code takes
     care of avoiding doubled opening quotes. */
  rlen = strlen (rtext);
  ret = xmalloc (rlen + 1);
  strcpy (ret, rtext);

  /* If there are multiple matches, cut off the closing quote. */
  if (rtype == MULT_MATCH && cs != COMPLETE_BSQUOTE)
    ret[rlen - 1] = '\0';
  free (rtext);
  return ret;
}
#endif

static inline int
skip_single_quoted (char *string, int sind)
{
  register int i;

  for (i = sind; string[i] && string[i] != '\''; i++)
    ;
  if (string[i])
    i++;
  return i;
}

static inline int
skip_double_quoted (char *string, int sind)
{
  register int i;

  for (i = sind; string[i] && string[i] != '\"'; i++)
    ;
  if (string[i])
    i++;
  return i;
}

/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
   an unclosed quoted string), or if the character at EINDEX is quoted
   by a backslash. */
int char_is_quoted (char *string, int eindex)
{
  int i, pass_next, quoted;

  for (i = pass_next = quoted = 0; i <= eindex; i++)
    {
      if (pass_next)
      {
        pass_next = 0;
        if (i >= eindex)      /* XXX was if (i >= eindex - 1) */
          return 1;
        continue;
      }
      else if (string[i] == '\'' || string[i] == '"')
      {
        i = (string[i] == '\'') ? skip_single_quoted (string, ++i)
                          : skip_double_quoted (string, ++i);
        if (i > eindex)
          return 1;
        i--;      /* the skip functions increment past the closing quote. */
      }
      else if (string[i] == '\\')
      {
        pass_next = 1;
        continue;
      }
    }
  return (0);
}

/* Quote STRING using double quotes.  Return a new string. */
char *bash_double_quote (char *string)
{
  register int c;
  char *result, *r, *s;

  result = (char *)xmalloc (3 + (2 * strlen (string)));
  r = result;
  *r++ = '"';

  for (s = string; s && (c = *s); s++)
    {
      switch (c)
        {
      case '"':
      case '$':
      case '`':
      case '\\':
        *r++ = '\\';
      default:
        *r++ = c;
        break;
        }
    }

  *r++ = '"';
  *r = '\0';

  return (result);
}

/* Return a new string which is the single-quoted version of STRING.
   Used by alias and trap, among others. */
char *bash_single_quote (char *string)
{
  register int c;
  char *result, *r, *s;

  result = (char *)xmalloc (3 + (4 * strlen (string)));
  r = result;
  *r++ = '\'';

  for (s = string; s && (c = *s); s++)
    {
      *r++ = c;

      if (c == '\'')
      {
        *r++ = '\\';    /* insert escaped single quote */
        *r++ = '\'';
        *r++ = '\'';    /* start new quoted string */
      }
    }

  *r++ = '\'';
  *r = '\0';

  return (result);
}

/* Quote special characters in STRING using backslashes.  Return a new
   string. */
char *bash_backslash_quote (char *string)
{
  int c;
  char *result, *r, *s;

  result = xmalloc (2 * strlen (string) + 1);

  for (r = result, s = string; s && (c = *s); s++)
    {
      switch (c)
      {
      case ' ': case '\t': case '\n':           /* IFS white space */
      case '\'': case '"': case '\\':           /* quoting chars */
      case '|': case '&': case ';':       /* shell metacharacters */
      case '(': case ')': case '<': case '>':
      case '!': case '{': case '}':       /* reserved words */
      case '*': case '[': case '?': case ']':   /* globbing chars */
      case '^':
      case '$': case '`':                 /* expansion chars */
        *r++ = '\\';
        *r++ = c;
        break;
      case '#':                     /* comment char */
#if 0
      case '~':                     /* tilde expansion */
#endif
        if (s == string)
          *r++ = '\\';
        /* FALLTHROUGH */
      default:
        *r++ = c;
        break;
      }
    }

  *r = '\0';
  return (result);
}

#ifdef HAVE_LIBREADLINE
/* Quote characters that the readline completion code would treat as
   word break characters with backslashes.  Pass backslash-quoted
   characters through without examination. */
char *quote_word_break_chars (char *text)
{
  char *ret, *r, *s;
  int l;

  l = strlen (text);
  ret = xmalloc ((2 * l) + 1);
  for (s = text, r = ret; *s; s++)
    {
      /* Pass backslash-quoted characters through, including the backslash. */
      if (*s == '\\')
      {
        *r++ = '\\';
        *r++ = *++s;
        if (*s == '\0')
          break;
        continue;
      }
      /* OK, we have an unquoted character.  Check its presence in
       rl_completer_word_break_characters. */
      if (strchr (rl_completer_word_break_characters, *s))
        *r++ = '\\';
      *r++ = *s;
    }
  *r = '\0';
  return ret;
}
#endif

Generated by  Doxygen 1.6.0   Back to index