1/*	$NetBSD$	*/
2
3/* Shell command argument quoting.
4   Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; see the file COPYING.
18   If not, write to the Free Software Foundation,
19   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21/* Written by Paul Eggert <eggert@twinsun.com> */
22
23#if HAVE_CONFIG_H
24# include <config.h>
25#endif
26
27#include <sys/types.h>
28#include <quotesys.h>
29
30/* Place into QUOTED a quoted version of ARG suitable for `system'.
31   Return the length of the resulting string (which is not null-terminated).
32   If QUOTED is null, return the length without any side effects.  */
33
34size_t
35quote_system_arg (quoted, arg)
36     char *quoted;
37     char const *arg;
38{
39  char const *a;
40  size_t len = 0;
41
42  /* Scan ARG, copying it to QUOTED if QUOTED is not null,
43     looking for shell metacharacters.  */
44
45  for (a = arg; ; a++)
46    {
47      char c = *a;
48      switch (c)
49	{
50	case 0:
51	  /* ARG has no shell metacharacters.  */
52	  return len;
53
54	case '=':
55	  if (*arg == '-')
56	    break;
57	  /* Fall through.  */
58	case '\t': case '\n': case ' ':
59	case '!': case '"': case '#': case '$': case '%': case '&': case '\'':
60	case '(': case ')': case '*': case ';':
61	case '<': case '>': case '?': case '[': case '\\':
62	case '^': case '`': case '|': case '~':
63	  {
64	    /* ARG has a shell metacharacter.
65	       Start over, quoting it this time.  */
66
67	    len = 0;
68	    c = *arg++;
69
70	    /* If ARG is an option, quote just its argument.
71	       This is not necessary, but it looks nicer.  */
72	    if (c == '-'  &&  arg < a)
73	      {
74		c = *arg++;
75
76		if (quoted)
77		  {
78		    quoted[len] = '-';
79		    quoted[len + 1] = c;
80		  }
81		len += 2;
82
83		if (c == '-')
84		  while (arg < a)
85		    {
86		      c = *arg++;
87		      if (quoted)
88			quoted[len] = c;
89		      len++;
90		      if (c == '=')
91			break;
92		    }
93		c = *arg++;
94	      }
95
96	    if (quoted)
97	      quoted[len] = '\'';
98	    len++;
99
100	    for (;  c;  c = *arg++)
101	      {
102		if (c == '\'')
103		  {
104		    if (quoted)
105		      {
106			quoted[len] = '\'';
107			quoted[len + 1] = '\\';
108			quoted[len + 2] = '\'';
109		      }
110		    len += 3;
111		  }
112		if (quoted)
113		  quoted[len] = c;
114		len++;
115	      }
116
117	    if (quoted)
118	      quoted[len] = '\'';
119	    return len + 1;
120	  }
121	}
122
123      if (quoted)
124	quoted[len] = c;
125      len++;
126    }
127}
128