1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
.\" $NetBSD: shquote.3,v 1.9 2008/09/07 08:55:46 apb Exp $
.\"
.\" Copyright (c) 2001 Christopher G. Demetriou
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed for the
.\" NetBSD Project. See http://www.NetBSD.org/ for
.\" information about NetBSD.
.\" 4. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
.\"
.Dd September 7, 2008
.Dt SHQUOTE 3
.Os
.Sh NAME
.Nm shquote ,
.Nm shquotev
.Nd quote argument strings for use with the shell
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
.In stdlib.h
.Ft size_t
.Fn shquote "const char *arg" "char *buf" "size_t bufsize"
.Ft size_t
.Fn shquotev "int argc" "char * const *argv" "char *buf" "size_t bufsize"
.Sh DESCRIPTION
The
.Fn shquote
and
.Fn shquotev
functions copy strings and transform the copies by adding shell
escape and quoting characters.
They are used to encapsulate
arguments to be included in command strings passed to the
.Fn system
and
.Fn popen
functions, so that the arguments will have the correct values
after being evaluated by the shell.
.Pp
The exact method of quoting and escaping may vary, and is intended
to match the conventions of the shell used by
.Fn system
and
.Fn popen .
It may not match the conventions used by other shells.
In this implementation, the following
transformation is applied to each input string:
.Bl -bullet -width indent
.It
it is surrounded by single quotes
.Pq ' ,
.It
any single quotes in the input are escaped by replacing them with
the four-character sequence:
.Li '\e'' ,
and
.It
extraneous pairs of single quotes (caused by multiple adjacent single
quotes in the input string, or by single quotes at the beginning or
end of the input string) are elided.
.El
.Pp
The
.Fn shquote
function transforms the string specified by its
.Fa arg
argument, and places the result into the memory pointed to by
.Fa buf .
.Pp
The
.Fn shquotev
function transforms each of the
.Fa argc
strings specified by the array
.Fa argv
independently.
The transformed strings are placed in the memory pointed to by
.Fa buf ,
separated by spaces.
It does not modify the pointer array specified by
.Fa argv
or the strings pointed to by the pointers in the array.
.Pp
Both functions write up to
.Fa bufsize
- 1 characters of output into the buffer pointed to by
.Fa buf ,
then add a
.Li NUL
character to terminate the output string.
If
.Fa bufsize
is given as zero, the
.Fa buf
parameter is ignored and no output is written.
.Sh RETURN VALUES
The
.Fn shquote
and
.Fn shquotev
functions return the number of characters necessary to hold the
result from operating on their input strings,
not including the terminating
.Li NUL .
That is, they return the length of the string that would have
been written to the output buffer, if it were large enough.
If an error occurs during processing, the value ((size_t)\-1)
is returned and
.Va errno
is set appropriately.
.Sh EXAMPLES
The following code fragment demonstrates how you might use
.Fn shquotev
to construct a command string to be used with
.Fn system .
The command uses an environment variable (which will be expanded by
the shell) to determine the actual program to run.
Note that the environment variable may be expanded by
the shell into multiple words.
The first word of the expansion will be used by the shell
as the name of the program to run,
and the rest will be passed as arguments to the program.
.Bd -literal -offset indent
char **argv, c, *cmd;
size_t cmdlen, len, qlen;
int argc;
\&...
/*
* Size buffer to hold the command string, and allocate it.
* Buffer of length one given to snprintf() for portability.
*/
cmdlen = snprintf(\*[Am]c, 1, "${PROG-%s} ", PROG_DEFAULT);
qlen = shquotev(argc, argv, NULL, 0);
if (qlen == (size_t)-1) {
\&...
}
cmdlen += qlen + 1;
cmd = malloc(cmdlen);
if (cmd == NULL) {
\&...
}
/* Create the command string. */
len = snprintf(cmd, cmdlen, "${PROG-%s} ", PROG_DEFAULT);
qlen = shquotev(argc, argv, cmd + len, cmdlen - len);
if (qlen == (size_t)-1) {
/* Should not ever happen. */
\&...
}
len += qlen;
/* "cmd" can now be passed to system(). */
.Ed
.Pp
The following example shows how you would implement the same
functionality using the
.Fn shquote
function directly.
.Bd -literal -offset indent
char **argv, c, *cmd;
size_t cmdlen, len, qlen;
int argc, i;
\&...
/*
* Size buffer to hold the command string, and allocate it.
* Buffer of length one given to snprintf() for portability.
*/
cmdlen = snprintf(\*[Am]c, 1, "${PROG-%s} ", PROG_DEFAULT);
for (i = 0; i \*[Lt] argc; i++) {
qlen = shquote(argv[i], NULL, 0);
if (qlen == (size_t)-1) {
\&...
}
cmdlen += qlen + 1;
}
cmd = malloc(cmdlen);
if (cmd == NULL) {
\&...
}
/* Start the command string with the env var reference. */
len = snprintf(cmd, cmdlen, "${PROG-%s} ", PROG_DEFAULT);
/* Quote all of the arguments when copying them. */
for (i = 0; i \*[Lt] argc; i++) {
qlen = shquote(argv[i], cmd + len, cmdlen - len);
if (qlen == (size_t)-1) {
/* Should not ever happen. */
\&...
}
len += qlen;
cmd[len++] = ' ';
}
cmd[--len] = '\e0';
/* "cmd" can now be passed to system(). */
.Ed
.Sh SEE ALSO
.Xr sh 1 ,
.Xr popen 3 ,
.Xr system 3
.Sh BUGS
This implementation does not currently handle strings containing multibyte
characters properly.
To address this issue,
.Pa /bin/sh
.Po
the shell used by
.Fn system
and
.Fn popen
.Pc
must first be fixed to handle multibyte characters.
When that has been done,
these functions can have multibyte character support enabled.
|