1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1997-2005
5  *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 /*
36  * String functions.
37  *
38  *	equal(s1, s2)		Return true if strings are equal.
39  *	scopy(from, to)		Copy a string.
40  *	scopyn(from, to, n)	Like scopy, but checks for overflow.
41  *	number(s)		Convert a string of digits to an integer.
42  *	is_number(s)		Return true if s is a string of digits.
43  */
44 
45 #include <ctype.h>
46 #include <errno.h>
47 #include <inttypes.h>
48 #include <limits.h>
49 #include <inttypes.h>
50 #include <stdlib.h>
51 #include "shell.h"
52 #include "syntax.h"
53 #include "error.h"
54 #include "mystring.h"
55 #include "memalloc.h"
56 #include "parser.h"
57 #include "system.h"
58 
59 
60 char nullstr[1];		/* zero length string */
61 const char spcstr[] = " ";
62 const char snlfmt[] = "%s\n";
63 const char dolatstr[] = { CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=',
64 			  CTLQUOTEMARK, '\0' };
65 const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
66 const char illnum[] = "Illegal number: %s";
67 const char homestr[] = "HOME";
68 
69 /*
70  * equal - #defined in mystring.h
71  */
72 
73 /*
74  * scopy - #defined in mystring.h
75  */
76 
77 
78 #if 0
79 /*
80  * scopyn - copy a string from "from" to "to", truncating the string
81  *		if necessary.  "To" is always nul terminated, even if
82  *		truncation is performed.  "Size" is the size of "to".
83  */
84 
85 void
86 scopyn(const char *from, char *to, int size)
87 {
88 
89 	while (--size > 0) {
90 		if ((*to++ = *from++) == '\0')
91 			return;
92 	}
93 	*to = '\0';
94 }
95 #endif
96 
97 
98 /*
99  * prefix -- see if pfx is a prefix of string.
100  */
101 
102 char *
prefix(const char * string,const char * pfx)103 prefix(const char *string, const char *pfx)
104 {
105 	while (*pfx) {
106 		if (*pfx++ != *string++)
107 			return 0;
108 	}
109 	return (char *) string;
110 }
111 
badnum(const char * s)112 void badnum(const char *s)
113 {
114 	sh_error(illnum, s);
115 }
116 
117 /*
118  * Convert a string into an integer of type intmax_t.  Alow trailing spaces.
119  */
atomax(const char * s,int base)120 intmax_t atomax(const char *s, int base)
121 {
122 	char *p;
123 	intmax_t r;
124 
125 	errno = 0;
126 	r = strtoimax(s, &p, base);
127 
128 	if (errno == ERANGE)
129 		badnum(s);
130 
131 	/*
132 	 * Disallow completely blank strings in non-arithmetic (base != 0)
133 	 * contexts.
134 	 */
135 	if (p == s && base)
136 		badnum(s);
137 
138 	while (isspace((unsigned char)*p))
139 	      p++;
140 
141 	if (*p)
142 		badnum(s);
143 
144 	return r;
145 }
146 
atomax10(const char * s)147 intmax_t atomax10(const char *s)
148 {
149 	return atomax(s, 10);
150 }
151 
152 /*
153  * Convert a string of digits to an integer, printing an error message on
154  * failure.
155  */
156 
157 int
number(const char * s)158 number(const char *s)
159 {
160 	intmax_t n = atomax10(s);
161 
162 	if (n < 0 || n > INT_MAX)
163 		badnum(s);
164 
165 	return n;
166 }
167 
168 
169 
170 /*
171  * Check for a valid number.  This should be elsewhere.
172  */
173 
174 int
is_number(const char * p)175 is_number(const char *p)
176 {
177 	do {
178 		if (! is_digit(*p))
179 			return 0;
180 	} while (*++p != '\0');
181 	return 1;
182 }
183 
184 
185 /*
186  * Produce a possibly single quoted string suitable as input to the shell.
187  * The return string is allocated on the stack.
188  */
189 
190 char *
single_quote(const char * s)191 single_quote(const char *s) {
192 	char *p;
193 
194 	STARTSTACKSTR(p);
195 
196 	do {
197 		char *q;
198 		size_t len;
199 
200 		len = strchrnul(s, '\'') - s;
201 
202 		q = p = makestrspace(len + 3, p);
203 
204 		*q++ = '\'';
205 		q = mempcpy(q, s, len);
206 		*q++ = '\'';
207 		s += len;
208 
209 		STADJUST(q - p, p);
210 
211 		len = strspn(s, "'");
212 		if (!len)
213 			break;
214 
215 		q = p = makestrspace(len + 3, p);
216 
217 		*q++ = '"';
218 		q = mempcpy(q, s, len);
219 		*q++ = '"';
220 		s += len;
221 
222 		STADJUST(q - p, p);
223 	} while (*s);
224 
225 	USTPUTC(0, p);
226 
227 	return stackblock();
228 }
229 
230 /*
231  * Like strdup but works with the ash stack.
232  */
233 
234 char *
sstrdup(const char * p)235 sstrdup(const char *p)
236 {
237 	size_t len = strlen(p) + 1;
238 	return memcpy(stalloc(len), p, len);
239 }
240 
241 /*
242  * Wrapper around strcmp for qsort/bsearch/...
243  */
244 int
pstrcmp(const void * a,const void * b)245 pstrcmp(const void *a, const void *b)
246 {
247 	return strcmp(*(const char *const *) a, *(const char *const *) b);
248 }
249 
250 /*
251  * Find a string is in a sorted array.
252  */
253 const char *const *
findstring(const char * s,const char * const * array,size_t nmemb)254 findstring(const char *s, const char *const *array, size_t nmemb)
255 {
256 	return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp);
257 }
258