csh: replace malloc(x * y) and realloc(x * y) with reallocarraydiff -r1.35 -r1.36 src/bin/csh/dir.c
(nia)
--- src/bin/csh/dir.c 2020/08/09 00:34:21 1.35
+++ src/bin/csh/dir.c 2024/04/24 15:49:03 1.36
@@ -1,903 +1,904 @@ | @@ -1,903 +1,904 @@ | |||
1 | /* $NetBSD: dir.c,v 1.35 2020/08/09 00:34:21 dholland Exp $ */ | 1 | /* $NetBSD: dir.c,v 1.36 2024/04/24 15:49:03 nia Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1980, 1991, 1993 | 4 | * Copyright (c) 1980, 1991, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the University nor the names of its contributors | 15 | * 3. Neither the name of the University nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | #if 0 | 34 | #if 0 | |
35 | static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 5/31/93"; | 35 | static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 5/31/93"; | |
36 | #else | 36 | #else | |
37 | __RCSID("$NetBSD: dir.c,v 1.35 2020/08/09 00:34:21 dholland Exp $"); | 37 | __RCSID("$NetBSD: dir.c,v 1.36 2024/04/24 15:49:03 nia Exp $"); | |
38 | #endif | 38 | #endif | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #include <sys/param.h> | 41 | #include <sys/param.h> | |
42 | #include <sys/stat.h> | 42 | #include <sys/stat.h> | |
43 | 43 | |||
44 | #include <errno.h> | 44 | #include <errno.h> | |
45 | #include <stdarg.h> | 45 | #include <stdarg.h> | |
46 | #include <stdlib.h> | 46 | #include <stdlib.h> | |
47 | #include <string.h> | 47 | #include <string.h> | |
48 | #include <unistd.h> | 48 | #include <unistd.h> | |
49 | 49 | |||
50 | #include "csh.h" | 50 | #include "csh.h" | |
51 | #include "dir.h" | 51 | #include "dir.h" | |
52 | #include "extern.h" | 52 | #include "extern.h" | |
53 | 53 | |||
54 | /* Directory management. */ | 54 | /* Directory management. */ | |
55 | 55 | |||
56 | static struct directory *dfind(Char *); | 56 | static struct directory *dfind(Char *); | |
57 | static Char *dfollow(Char *); | 57 | static Char *dfollow(Char *); | |
58 | static void printdirs(void); | 58 | static void printdirs(void); | |
59 | static Char *dgoto(Char *); | 59 | static Char *dgoto(Char *); | |
60 | static void skipargs(Char ***, const char *); | 60 | static void skipargs(Char ***, const char *); | |
61 | static void dnewcwd(struct directory *); | 61 | static void dnewcwd(struct directory *); | |
62 | static void dset(Char *); | 62 | static void dset(Char *); | |
63 | 63 | |||
64 | struct directory dhead; /* "head" of loop */ | 64 | struct directory dhead; /* "head" of loop */ | |
65 | int printd; /* force name to be printed */ | 65 | int printd; /* force name to be printed */ | |
66 | 66 | |||
67 | static int dirflag = 0; | 67 | static int dirflag = 0; | |
68 | 68 | |||
69 | struct directory *dcwd; | 69 | struct directory *dcwd; | |
70 | 70 | |||
71 | /* | 71 | /* | |
72 | * dinit - initialize current working directory | 72 | * dinit - initialize current working directory | |
73 | */ | 73 | */ | |
74 | void | 74 | void | |
75 | dinit(Char *hp) | 75 | dinit(Char *hp) | |
76 | { | 76 | { | |
77 | static const char emsg[] = "csh: Trying to start from \"%s\"\n"; | 77 | static const char emsg[] = "csh: Trying to start from \"%s\"\n"; | |
78 | char path[MAXPATHLEN]; | 78 | char path[MAXPATHLEN]; | |
79 | struct directory *dp; | 79 | struct directory *dp; | |
80 | const char *ecp; | 80 | const char *ecp; | |
81 | Char *cp; | 81 | Char *cp; | |
82 | 82 | |||
83 | /* Don't believe the login shell home, because it may be a symlink */ | 83 | /* Don't believe the login shell home, because it may be a symlink */ | |
84 | ecp = getcwd(path, MAXPATHLEN); | 84 | ecp = getcwd(path, MAXPATHLEN); | |
85 | if (ecp == NULL || *ecp == '\0') { | 85 | if (ecp == NULL || *ecp == '\0') { | |
86 | (void)fprintf(csherr, "csh: %s\n", strerror(errno)); | 86 | (void)fprintf(csherr, "csh: %s\n", strerror(errno)); | |
87 | if (hp && *hp) { | 87 | if (hp && *hp) { | |
88 | ecp = short2str(hp); | 88 | ecp = short2str(hp); | |
89 | if (chdir(ecp) == -1) | 89 | if (chdir(ecp) == -1) | |
90 | cp = NULL; | 90 | cp = NULL; | |
91 | else | 91 | else | |
92 | cp = Strsave(hp); | 92 | cp = Strsave(hp); | |
93 | (void)fprintf(csherr, emsg, vis_str(hp)); | 93 | (void)fprintf(csherr, emsg, vis_str(hp)); | |
94 | } | 94 | } | |
95 | else | 95 | else | |
96 | cp = NULL; | 96 | cp = NULL; | |
97 | if (cp == NULL) { | 97 | if (cp == NULL) { | |
98 | (void)fprintf(csherr, emsg, "/"); | 98 | (void)fprintf(csherr, emsg, "/"); | |
99 | if (chdir("/") == -1) { | 99 | if (chdir("/") == -1) { | |
100 | /* I am not even try to print an error message! */ | 100 | /* I am not even try to print an error message! */ | |
101 | xexit(1); | 101 | xexit(1); | |
102 | } | 102 | } | |
103 | cp = SAVE("/"); | 103 | cp = SAVE("/"); | |
104 | } | 104 | } | |
105 | } | 105 | } | |
106 | else { | 106 | else { | |
107 | struct stat swd, shp; | 107 | struct stat swd, shp; | |
108 | 108 | |||
109 | /* | 109 | /* | |
110 | * See if $HOME is the working directory we got and use that | 110 | * See if $HOME is the working directory we got and use that | |
111 | */ | 111 | */ | |
112 | if (hp && *hp && | 112 | if (hp && *hp && | |
113 | stat(ecp, &swd) != -1 && stat(short2str(hp), &shp) != -1 && | 113 | stat(ecp, &swd) != -1 && stat(short2str(hp), &shp) != -1 && | |
114 | swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino) | 114 | swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino) | |
115 | cp = Strsave(hp); | 115 | cp = Strsave(hp); | |
116 | else { | 116 | else { | |
117 | const char *cwd; | 117 | const char *cwd; | |
118 | 118 | |||
119 | /* | 119 | /* | |
120 | * use PWD if we have it (for subshells) | 120 | * use PWD if we have it (for subshells) | |
121 | */ | 121 | */ | |
122 | if ((cwd = getenv("PWD")) != NULL) { | 122 | if ((cwd = getenv("PWD")) != NULL) { | |
123 | if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev && | 123 | if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev && | |
124 | swd.st_ino == shp.st_ino) | 124 | swd.st_ino == shp.st_ino) | |
125 | ecp = cwd; | 125 | ecp = cwd; | |
126 | } | 126 | } | |
127 | cp = dcanon(SAVE(ecp), STRNULL); | 127 | cp = dcanon(SAVE(ecp), STRNULL); | |
128 | } | 128 | } | |
129 | } | 129 | } | |
130 | 130 | |||
131 | dp = xcalloc(1, sizeof(*dp)); | 131 | dp = xcalloc(1, sizeof(*dp)); | |
132 | dp->di_name = cp; | 132 | dp->di_name = cp; | |
133 | dp->di_count = 0; | 133 | dp->di_count = 0; | |
134 | dhead.di_next = dhead.di_prev = dp; | 134 | dhead.di_next = dhead.di_prev = dp; | |
135 | dp->di_next = dp->di_prev = &dhead; | 135 | dp->di_next = dp->di_prev = &dhead; | |
136 | printd = 0; | 136 | printd = 0; | |
137 | dnewcwd(dp); | 137 | dnewcwd(dp); | |
138 | } | 138 | } | |
139 | 139 | |||
140 | static void | 140 | static void | |
141 | dset(Char *dp) | 141 | dset(Char *dp) | |
142 | { | 142 | { | |
143 | Char **vec; | 143 | Char **vec; | |
144 | 144 | |||
145 | /* | 145 | /* | |
146 | * Don't call set() directly cause if the directory contains ` or | 146 | * Don't call set() directly cause if the directory contains ` or | |
147 | * other junk characters glob will fail. | 147 | * other junk characters glob will fail. | |
148 | */ | 148 | */ | |
149 | 149 | |||
150 | vec = xmalloc(2 * sizeof(*vec)); | 150 | vec = xmalloc(2 * sizeof(*vec)); | |
151 | vec[0] = Strsave(dp); | 151 | vec[0] = Strsave(dp); | |
152 | vec[1] = 0; | 152 | vec[1] = 0; | |
153 | setq(STRcwd, vec, &shvhed); | 153 | setq(STRcwd, vec, &shvhed); | |
154 | Setenv(STRPWD, dp); | 154 | Setenv(STRPWD, dp); | |
155 | } | 155 | } | |
156 | 156 | |||
157 | #define DIR_LONG 1 | 157 | #define DIR_LONG 1 | |
158 | #define DIR_VERT 2 | 158 | #define DIR_VERT 2 | |
159 | #define DIR_LINE 4 | 159 | #define DIR_LINE 4 | |
160 | 160 | |||
161 | static void | 161 | static void | |
162 | skipargs(Char ***v, const char *str) | 162 | skipargs(Char ***v, const char *str) | |
163 | { | 163 | { | |
164 | Char **n, *s; | 164 | Char **n, *s; | |
165 | 165 | |||
166 | n = *v; | 166 | n = *v; | |
167 | dirflag = 0; | 167 | dirflag = 0; | |
168 | for (n++; *n != NULL && (*n)[0] == '-'; n++) | 168 | for (n++; *n != NULL && (*n)[0] == '-'; n++) | |
169 | for (s = &((*n)[1]); *s; s++) | 169 | for (s = &((*n)[1]); *s; s++) | |
170 | switch (*s) { | 170 | switch (*s) { | |
171 | case 'l': | 171 | case 'l': | |
172 | dirflag |= DIR_LONG; | 172 | dirflag |= DIR_LONG; | |
173 | break; | 173 | break; | |
174 | case 'n': | 174 | case 'n': | |
175 | dirflag |= DIR_LINE; | 175 | dirflag |= DIR_LINE; | |
176 | break; | 176 | break; | |
177 | case 'v': | 177 | case 'v': | |
178 | dirflag |= DIR_VERT; | 178 | dirflag |= DIR_VERT; | |
179 | break; | 179 | break; | |
180 | default: | 180 | default: | |
181 | stderror(ERR_DIRUS, vis_str(**v), str); | 181 | stderror(ERR_DIRUS, vis_str(**v), str); | |
182 | /* NOTREACHED */ | 182 | /* NOTREACHED */ | |
183 | } | 183 | } | |
184 | *v = n; | 184 | *v = n; | |
185 | } | 185 | } | |
186 | 186 | |||
187 | /* | 187 | /* | |
188 | * dodirs - list all directories in directory loop | 188 | * dodirs - list all directories in directory loop | |
189 | */ | 189 | */ | |
190 | void | 190 | void | |
191 | /*ARGSUSED*/ | 191 | /*ARGSUSED*/ | |
192 | dodirs(Char **v, struct command *t) | 192 | dodirs(Char **v, struct command *t) | |
193 | { | 193 | { | |
194 | skipargs(&v, ""); | 194 | skipargs(&v, ""); | |
195 | 195 | |||
196 | if (*v != NULL) | 196 | if (*v != NULL) | |
197 | stderror(ERR_DIRUS, "dirs", ""); | 197 | stderror(ERR_DIRUS, "dirs", ""); | |
198 | printdirs(); | 198 | printdirs(); | |
199 | } | 199 | } | |
200 | 200 | |||
201 | static void | 201 | static void | |
202 | printdirs(void) | 202 | printdirs(void) | |
203 | { | 203 | { | |
204 | struct directory *dp; | 204 | struct directory *dp; | |
205 | Char *hp, *s; | 205 | Char *hp, *s; | |
206 | size_t cur, idx, len; | 206 | size_t cur, idx, len; | |
207 | 207 | |||
208 | hp = value(STRhome); | 208 | hp = value(STRhome); | |
209 | if (*hp == '\0') | 209 | if (*hp == '\0') | |
210 | hp = NULL; | 210 | hp = NULL; | |
211 | dp = dcwd; | 211 | dp = dcwd; | |
212 | idx = 0; | 212 | idx = 0; | |
213 | cur = 0; | 213 | cur = 0; | |
214 | do { | 214 | do { | |
215 | if (dp == &dhead) | 215 | if (dp == &dhead) | |
216 | continue; | 216 | continue; | |
217 | if (dirflag & DIR_VERT) { | 217 | if (dirflag & DIR_VERT) { | |
218 | (void)fprintf(cshout, "%zu\t", idx++); | 218 | (void)fprintf(cshout, "%zu\t", idx++); | |
219 | cur = 0; | 219 | cur = 0; | |
220 | } | 220 | } | |
221 | if (!(dirflag & DIR_LONG) && hp != NULL && !eq(hp, STRslash) && | 221 | if (!(dirflag & DIR_LONG) && hp != NULL && !eq(hp, STRslash) && | |
222 | (len = Strlen(hp), Strncmp(hp, dp->di_name, len) == 0) && | 222 | (len = Strlen(hp), Strncmp(hp, dp->di_name, len) == 0) && | |
223 | (dp->di_name[len] == '\0' || dp->di_name[len] == '/')) | 223 | (dp->di_name[len] == '\0' || dp->di_name[len] == '/')) | |
224 | len = Strlen(s = (dp->di_name + len)) + 2; | 224 | len = Strlen(s = (dp->di_name + len)) + 2; | |
225 | else | 225 | else | |
226 | len = Strlen(s = dp->di_name) + 1; | 226 | len = Strlen(s = dp->di_name) + 1; | |
227 | 227 | |||
228 | cur += len; | 228 | cur += len; | |
229 | if ((dirflag & DIR_LINE) && cur >= 80 - 1 && len < 80) { | 229 | if ((dirflag & DIR_LINE) && cur >= 80 - 1 && len < 80) { | |
230 | (void)fprintf(cshout, "\n"); | 230 | (void)fprintf(cshout, "\n"); | |
231 | cur = len; | 231 | cur = len; | |
232 | } | 232 | } | |
233 | (void) fprintf(cshout, "%s%s%c", (s != dp->di_name)? "~" : "", | 233 | (void) fprintf(cshout, "%s%s%c", (s != dp->di_name)? "~" : "", | |
234 | vis_str(s), (dirflag & DIR_VERT) ? '\n' : ' '); | 234 | vis_str(s), (dirflag & DIR_VERT) ? '\n' : ' '); | |
235 | } while ((dp = dp->di_prev) != dcwd); | 235 | } while ((dp = dp->di_prev) != dcwd); | |
236 | if (!(dirflag & DIR_VERT)) | 236 | if (!(dirflag & DIR_VERT)) | |
237 | (void)fprintf(cshout, "\n"); | 237 | (void)fprintf(cshout, "\n"); | |
238 | } | 238 | } | |
239 | 239 | |||
240 | void | 240 | void | |
241 | dtildepr(Char *home, Char *dir) | 241 | dtildepr(Char *home, Char *dir) | |
242 | { | 242 | { | |
243 | if (!eq(home, STRslash) && prefix(home, dir)) | 243 | if (!eq(home, STRslash) && prefix(home, dir)) | |
244 | (void)fprintf(cshout, "~%s", vis_str(dir + Strlen(home))); | 244 | (void)fprintf(cshout, "~%s", vis_str(dir + Strlen(home))); | |
245 | else | 245 | else | |
246 | (void)fprintf(cshout, "%s", vis_str(dir)); | 246 | (void)fprintf(cshout, "%s", vis_str(dir)); | |
247 | } | 247 | } | |
248 | 248 | |||
249 | void | 249 | void | |
250 | dtilde(void) | 250 | dtilde(void) | |
251 | { | 251 | { | |
252 | struct directory *d; | 252 | struct directory *d; | |
253 | 253 | |||
254 | d = dcwd; | 254 | d = dcwd; | |
255 | do { | 255 | do { | |
256 | if (d == &dhead) | 256 | if (d == &dhead) | |
257 | continue; | 257 | continue; | |
258 | d->di_name = dcanon(d->di_name, STRNULL); | 258 | d->di_name = dcanon(d->di_name, STRNULL); | |
259 | } while ((d = d->di_prev) != dcwd); | 259 | } while ((d = d->di_prev) != dcwd); | |
260 | 260 | |||
261 | dset(dcwd->di_name); | 261 | dset(dcwd->di_name); | |
262 | } | 262 | } | |
263 | 263 | |||
264 | 264 | |||
265 | /* dnormalize(): | 265 | /* dnormalize(): | |
266 | * If the name starts with . or .. then we might need to normalize | 266 | * If the name starts with . or .. then we might need to normalize | |
267 | * it depending on the symbolic link flags | 267 | * it depending on the symbolic link flags | |
268 | */ | 268 | */ | |
269 | Char * | 269 | Char * | |
270 | dnormalize(Char *cp) | 270 | dnormalize(Char *cp) | |
271 | { | 271 | { | |
272 | #define UC (unsigned char) | 272 | #define UC (unsigned char) | |
273 | #define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/'))) | 273 | #define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/'))) | |
274 | #define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1]))) | 274 | #define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1]))) | |
275 | if ((unsigned char) cp[0] == '/') | 275 | if ((unsigned char) cp[0] == '/') | |
276 | return (Strsave(cp)); | 276 | return (Strsave(cp)); | |
277 | 277 | |||
278 | if (adrof(STRignore_symlinks)) { | 278 | if (adrof(STRignore_symlinks)) { | |
279 | size_t dotdot = 0; | 279 | size_t dotdot = 0; | |
280 | Char *dp, *cwd; | 280 | Char *dp, *cwd; | |
281 | 281 | |||
282 | cwd = xmalloc((size_t)((Strlen(dcwd->di_name) + 3) * | 282 | cwd = xreallocarray(NULL, (size_t)(Strlen(dcwd->di_name) + 3), | |
283 | sizeof(Char))); | 283 | sizeof(Char)); | |
284 | (void)Strcpy(cwd, dcwd->di_name); | 284 | (void)Strcpy(cwd, dcwd->di_name); | |
285 | 285 | |||
286 | /* | 286 | /* | |
287 | * Ignore . and count ..'s | 287 | * Ignore . and count ..'s | |
288 | */ | 288 | */ | |
289 | while (*cp) { | 289 | while (*cp) { | |
290 | if (ISDOT(cp)) { | 290 | if (ISDOT(cp)) { | |
291 | if (*++cp) | 291 | if (*++cp) | |
292 | cp++; | 292 | cp++; | |
293 | } | 293 | } | |
294 | else if (ISDOTDOT(cp)) { | 294 | else if (ISDOTDOT(cp)) { | |
295 | dotdot++; | 295 | dotdot++; | |
296 | cp += 2; | 296 | cp += 2; | |
297 | if (*cp) | 297 | if (*cp) | |
298 | cp++; | 298 | cp++; | |
299 | } | 299 | } | |
300 | else | 300 | else | |
301 | break; | 301 | break; | |
302 | } | 302 | } | |
303 | while (dotdot > 0) { | 303 | while (dotdot > 0) { | |
304 | dp = Strrchr(cwd, '/'); | 304 | dp = Strrchr(cwd, '/'); | |
305 | if (dp) { | 305 | if (dp) { | |
306 | *dp = '\0'; | 306 | *dp = '\0'; | |
307 | dotdot--; | 307 | dotdot--; | |
308 | } | 308 | } | |
309 | else | 309 | else | |
310 | break; | 310 | break; | |
311 | } | 311 | } | |
312 | 312 | |||
313 | if (*cp) { | 313 | if (*cp) { | |
314 | cwd[dotdot = Strlen(cwd)] = '/'; | 314 | cwd[dotdot = Strlen(cwd)] = '/'; | |
315 | cwd[dotdot + 1] = '\0'; | 315 | cwd[dotdot + 1] = '\0'; | |
316 | dp = Strspl(cwd, cp); | 316 | dp = Strspl(cwd, cp); | |
317 | free(cwd); | 317 | free(cwd); | |
318 | return dp; | 318 | return dp; | |
319 | } | 319 | } | |
320 | else { | 320 | else { | |
321 | if (!*cwd) { | 321 | if (!*cwd) { | |
322 | cwd[0] = '/'; | 322 | cwd[0] = '/'; | |
323 | cwd[1] = '\0'; | 323 | cwd[1] = '\0'; | |
324 | } | 324 | } | |
325 | return cwd; | 325 | return cwd; | |
326 | } | 326 | } | |
327 | } | 327 | } | |
328 | return Strsave(cp); | 328 | return Strsave(cp); | |
329 | } | 329 | } | |
330 | 330 | |||
331 | /* | 331 | /* | |
332 | * dochngd - implement chdir command. | 332 | * dochngd - implement chdir command. | |
333 | */ | 333 | */ | |
334 | void | 334 | void | |
335 | /*ARGSUSED*/ | 335 | /*ARGSUSED*/ | |
336 | dochngd(Char **v, struct command *t) | 336 | dochngd(Char **v, struct command *t) | |
337 | { | 337 | { | |
338 | struct directory *dp; | 338 | struct directory *dp; | |
339 | Char *cp; | 339 | Char *cp; | |
340 | 340 | |||
341 | skipargs(&v, " [<dir>]"); | 341 | skipargs(&v, " [<dir>]"); | |
342 | printd = 0; | 342 | printd = 0; | |
343 | if (*v == NULL) { | 343 | if (*v == NULL) { | |
344 | if ((cp = value(STRhome)) == NULL || *cp == 0) | 344 | if ((cp = value(STRhome)) == NULL || *cp == 0) | |
345 | stderror(ERR_NAME | ERR_NOHOMEDIR); | 345 | stderror(ERR_NAME | ERR_NOHOMEDIR); | |
346 | if (chdir(short2str(cp)) < 0) | 346 | if (chdir(short2str(cp)) < 0) | |
347 | stderror(ERR_NAME | ERR_CANTCHANGE); | 347 | stderror(ERR_NAME | ERR_CANTCHANGE); | |
348 | cp = Strsave(cp); | 348 | cp = Strsave(cp); | |
349 | } | 349 | } | |
350 | else if (v[1] != NULL) | 350 | else if (v[1] != NULL) | |
351 | stderror(ERR_NAME | ERR_TOOMANY); | 351 | stderror(ERR_NAME | ERR_TOOMANY); | |
352 | else if ((dp = dfind(*v)) != 0) { | 352 | else if ((dp = dfind(*v)) != 0) { | |
353 | char *tmp; | 353 | char *tmp; | |
354 | 354 | |||
355 | printd = 1; | 355 | printd = 1; | |
356 | if (chdir(tmp = short2str(dp->di_name)) < 0) | 356 | if (chdir(tmp = short2str(dp->di_name)) < 0) | |
357 | stderror(ERR_SYSTEM, tmp, strerror(errno)); | 357 | stderror(ERR_SYSTEM, tmp, strerror(errno)); | |
358 | dcwd->di_prev->di_next = dcwd->di_next; | 358 | dcwd->di_prev->di_next = dcwd->di_next; | |
359 | dcwd->di_next->di_prev = dcwd->di_prev; | 359 | dcwd->di_next->di_prev = dcwd->di_prev; | |
360 | dfree(dcwd); | 360 | dfree(dcwd); | |
361 | dnewcwd(dp); | 361 | dnewcwd(dp); | |
362 | return; | 362 | return; | |
363 | } | 363 | } | |
364 | else | 364 | else | |
365 | cp = dfollow(*v); | 365 | cp = dfollow(*v); | |
366 | dp = xcalloc(1, sizeof(*dp)); | 366 | dp = xcalloc(1, sizeof(*dp)); | |
367 | dp->di_name = cp; | 367 | dp->di_name = cp; | |
368 | dp->di_count = 0; | 368 | dp->di_count = 0; | |
369 | dp->di_next = dcwd->di_next; | 369 | dp->di_next = dcwd->di_next; | |
370 | dp->di_prev = dcwd->di_prev; | 370 | dp->di_prev = dcwd->di_prev; | |
371 | dp->di_prev->di_next = dp; | 371 | dp->di_prev->di_next = dp; | |
372 | dp->di_next->di_prev = dp; | 372 | dp->di_next->di_prev = dp; | |
373 | dfree(dcwd); | 373 | dfree(dcwd); | |
374 | dnewcwd(dp); | 374 | dnewcwd(dp); | |
375 | } | 375 | } | |
376 | 376 | |||
377 | static Char * | 377 | static Char * | |
378 | dgoto(Char *cp) | 378 | dgoto(Char *cp) | |
379 | { | 379 | { | |
380 | Char *dp; | 380 | Char *dp; | |
381 | 381 | |||
382 | if (*cp != '/') { | 382 | if (*cp != '/') { | |
383 | Char *p, *q; | 383 | Char *p, *q; | |
384 | size_t cwdlen; | 384 | size_t cwdlen; | |
385 | 385 | |||
386 | for (p = dcwd->di_name; *p++;) | 386 | for (p = dcwd->di_name; *p++;) | |
387 | continue; | 387 | continue; | |
388 | if ((cwdlen = (size_t)(p - dcwd->di_name - 1)) == 1) /* root */ | 388 | if ((cwdlen = (size_t)(p - dcwd->di_name - 1)) == 1) /* root */ | |
389 | cwdlen = 0; | 389 | cwdlen = 0; | |
390 | for (p = cp; *p++;) | 390 | for (p = cp; *p++;) | |
391 | continue; | 391 | continue; | |
392 | dp = xmalloc((size_t)(cwdlen + (size_t)(p - cp) + 1) * sizeof(Char)); | 392 | dp = xreallocarray(NULL, | |
393 | (size_t)(cwdlen + (size_t)(p - cp) + 1), sizeof(Char)); | |||
393 | for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';) | 394 | for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';) | |
394 | continue; | 395 | continue; | |
395 | if (cwdlen) | 396 | if (cwdlen) | |
396 | p[-1] = '/'; | 397 | p[-1] = '/'; | |
397 | else | 398 | else | |
398 | p--; /* don't add a / after root */ | 399 | p--; /* don't add a / after root */ | |
399 | for (q = cp; (*p++ = *q++) != '\0';) | 400 | for (q = cp; (*p++ = *q++) != '\0';) | |
400 | continue; | 401 | continue; | |
401 | free(cp); | 402 | free(cp); | |
402 | cp = dp; | 403 | cp = dp; | |
403 | dp += cwdlen; | 404 | dp += cwdlen; | |
404 | } | 405 | } | |
405 | else | 406 | else | |
406 | dp = cp; | 407 | dp = cp; | |
407 | 408 | |||
408 | cp = dcanon(cp, dp); | 409 | cp = dcanon(cp, dp); | |
409 | return cp; | 410 | return cp; | |
410 | } | 411 | } | |
411 | 412 | |||
412 | /* | 413 | /* | |
413 | * dfollow - change to arg directory; fall back on cdpath if not valid | 414 | * dfollow - change to arg directory; fall back on cdpath if not valid | |
414 | */ | 415 | */ | |
415 | static Char * | 416 | static Char * | |
416 | dfollow(Char *cp) | 417 | dfollow(Char *cp) | |
417 | { | 418 | { | |
418 | char ebuf[MAXPATHLEN]; | 419 | char ebuf[MAXPATHLEN]; | |
419 | struct varent *c; | 420 | struct varent *c; | |
420 | Char *dp; | 421 | Char *dp; | |
421 | int serrno; | 422 | int serrno; | |
422 | 423 | |||
423 | cp = globone(cp, G_ERROR); | 424 | cp = globone(cp, G_ERROR); | |
424 | /* | 425 | /* | |
425 | * if we are ignoring symlinks, try to fix relatives now. | 426 | * if we are ignoring symlinks, try to fix relatives now. | |
426 | */ | 427 | */ | |
427 | dp = dnormalize(cp); | 428 | dp = dnormalize(cp); | |
428 | if (chdir(short2str(dp)) >= 0) { | 429 | if (chdir(short2str(dp)) >= 0) { | |
429 | free(cp); | 430 | free(cp); | |
430 | return dgoto(dp); | 431 | return dgoto(dp); | |
431 | } | 432 | } | |
432 | else { | 433 | else { | |
433 | free(dp); | 434 | free(dp); | |
434 | if (chdir(short2str(cp)) >= 0) | 435 | if (chdir(short2str(cp)) >= 0) | |
435 | return dgoto(cp); | 436 | return dgoto(cp); | |
436 | serrno = errno; | 437 | serrno = errno; | |
437 | } | 438 | } | |
438 | 439 | |||
439 | if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp) | 440 | if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp) | |
440 | && (c = adrof(STRcdpath))) { | 441 | && (c = adrof(STRcdpath))) { | |
441 | Char **cdp; | 442 | Char **cdp; | |
442 | Char *p; | 443 | Char *p; | |
443 | Char buf[MAXPATHLEN]; | 444 | Char buf[MAXPATHLEN]; | |
444 | 445 | |||
445 | for (cdp = c->vec; *cdp; cdp++) { | 446 | for (cdp = c->vec; *cdp; cdp++) { | |
446 | for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';) | 447 | for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';) | |
447 | continue; | 448 | continue; | |
448 | dp[-1] = '/'; | 449 | dp[-1] = '/'; | |
449 | for (p = cp; (*dp++ = *p++) != '\0';) | 450 | for (p = cp; (*dp++ = *p++) != '\0';) | |
450 | continue; | 451 | continue; | |
451 | if (chdir(short2str(buf)) >= 0) { | 452 | if (chdir(short2str(buf)) >= 0) { | |
452 | printd = 1; | 453 | printd = 1; | |
453 | free(cp); | 454 | free(cp); | |
454 | cp = Strsave(buf); | 455 | cp = Strsave(buf); | |
455 | return dgoto(cp); | 456 | return dgoto(cp); | |
456 | } | 457 | } | |
457 | } | 458 | } | |
458 | } | 459 | } | |
459 | dp = value(cp); | 460 | dp = value(cp); | |
460 | if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) { | 461 | if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) { | |
461 | free(cp); | 462 | free(cp); | |
462 | cp = Strsave(dp); | 463 | cp = Strsave(dp); | |
463 | printd = 1; | 464 | printd = 1; | |
464 | return dgoto(cp); | 465 | return dgoto(cp); | |
465 | } | 466 | } | |
466 | (void)strcpy(ebuf, short2str(cp)); | 467 | (void)strcpy(ebuf, short2str(cp)); | |
467 | free(cp); | 468 | free(cp); | |
468 | stderror(ERR_SYSTEM, ebuf, strerror(serrno)); | 469 | stderror(ERR_SYSTEM, ebuf, strerror(serrno)); | |
469 | /* NOTREACHED */ | 470 | /* NOTREACHED */ | |
470 | } | 471 | } | |
471 | 472 | |||
472 | /* | 473 | /* | |
473 | * dopushd - push new directory onto directory stack. | 474 | * dopushd - push new directory onto directory stack. | |
474 | * with no arguments exchange top and second. | 475 | * with no arguments exchange top and second. | |
475 | * with numeric argument (+n) bring it to top. | 476 | * with numeric argument (+n) bring it to top. | |
476 | */ | 477 | */ | |
477 | void | 478 | void | |
478 | /*ARGSUSED*/ | 479 | /*ARGSUSED*/ | |
479 | dopushd(Char **v, struct command *t) | 480 | dopushd(Char **v, struct command *t) | |
480 | { | 481 | { | |
481 | struct directory *dp; | 482 | struct directory *dp; | |
482 | 483 | |||
483 | skipargs(&v, " [<dir>|+<n>]"); | 484 | skipargs(&v, " [<dir>|+<n>]"); | |
484 | printd = 1; | 485 | printd = 1; | |
485 | if (*v == NULL) { | 486 | if (*v == NULL) { | |
486 | char *tmp; | 487 | char *tmp; | |
487 | 488 | |||
488 | if ((dp = dcwd->di_prev) == &dhead) | 489 | if ((dp = dcwd->di_prev) == &dhead) | |
489 | dp = dhead.di_prev; | 490 | dp = dhead.di_prev; | |
490 | if (dp == dcwd) | 491 | if (dp == dcwd) | |
491 | stderror(ERR_NAME | ERR_NODIR); | 492 | stderror(ERR_NAME | ERR_NODIR); | |
492 | if (chdir(tmp = short2str(dp->di_name)) < 0) | 493 | if (chdir(tmp = short2str(dp->di_name)) < 0) | |
493 | stderror(ERR_SYSTEM, tmp, strerror(errno)); | 494 | stderror(ERR_SYSTEM, tmp, strerror(errno)); | |
494 | dp->di_prev->di_next = dp->di_next; | 495 | dp->di_prev->di_next = dp->di_next; | |
495 | dp->di_next->di_prev = dp->di_prev; | 496 | dp->di_next->di_prev = dp->di_prev; | |
496 | dp->di_next = dcwd->di_next; | 497 | dp->di_next = dcwd->di_next; | |
497 | dp->di_prev = dcwd; | 498 | dp->di_prev = dcwd; | |
498 | dcwd->di_next->di_prev = dp; | 499 | dcwd->di_next->di_prev = dp; | |
499 | dcwd->di_next = dp; | 500 | dcwd->di_next = dp; | |
500 | } | 501 | } | |
501 | else if (v[1] != NULL) | 502 | else if (v[1] != NULL) | |
502 | stderror(ERR_NAME | ERR_TOOMANY); | 503 | stderror(ERR_NAME | ERR_TOOMANY); | |
503 | else if ((dp = dfind(*v)) != NULL) { | 504 | else if ((dp = dfind(*v)) != NULL) { | |
504 | char *tmp; | 505 | char *tmp; | |
505 | 506 | |||
506 | if (chdir(tmp = short2str(dp->di_name)) < 0) | 507 | if (chdir(tmp = short2str(dp->di_name)) < 0) | |
507 | stderror(ERR_SYSTEM, tmp, strerror(errno)); | 508 | stderror(ERR_SYSTEM, tmp, strerror(errno)); | |
508 | } | 509 | } | |
509 | else { | 510 | else { | |
510 | Char *ccp; | 511 | Char *ccp; | |
511 | 512 | |||
512 | ccp = dfollow(*v); | 513 | ccp = dfollow(*v); | |
513 | dp = xcalloc(1, sizeof(*dp)); | 514 | dp = xcalloc(1, sizeof(*dp)); | |
514 | dp->di_name = ccp; | 515 | dp->di_name = ccp; | |
515 | dp->di_count = 0; | 516 | dp->di_count = 0; | |
516 | dp->di_prev = dcwd; | 517 | dp->di_prev = dcwd; | |
517 | dp->di_next = dcwd->di_next; | 518 | dp->di_next = dcwd->di_next; | |
518 | dcwd->di_next = dp; | 519 | dcwd->di_next = dp; | |
519 | dp->di_next->di_prev = dp; | 520 | dp->di_next->di_prev = dp; | |
520 | } | 521 | } | |
521 | dnewcwd(dp); | 522 | dnewcwd(dp); | |
522 | } | 523 | } | |
523 | 524 | |||
524 | /* | 525 | /* | |
525 | * dfind - find a directory if specified by numeric (+n) argument | 526 | * dfind - find a directory if specified by numeric (+n) argument | |
526 | */ | 527 | */ | |
527 | static struct directory * | 528 | static struct directory * | |
528 | dfind(Char *cp) | 529 | dfind(Char *cp) | |
529 | { | 530 | { | |
530 | struct directory *dp; | 531 | struct directory *dp; | |
531 | Char *ep; | 532 | Char *ep; | |
532 | int i; | 533 | int i; | |
533 | 534 | |||
534 | if (*cp++ != '+') | 535 | if (*cp++ != '+') | |
535 | return (0); | 536 | return (0); | |
536 | for (ep = cp; Isdigit(*ep); ep++) | 537 | for (ep = cp; Isdigit(*ep); ep++) | |
537 | continue; | 538 | continue; | |
538 | if (*ep) | 539 | if (*ep) | |
539 | return (0); | 540 | return (0); | |
540 | i = getn(cp); | 541 | i = getn(cp); | |
541 | if (i <= 0) | 542 | if (i <= 0) | |
542 | return (0); | 543 | return (0); | |
543 | for (dp = dcwd; i != 0; i--) { | 544 | for (dp = dcwd; i != 0; i--) { | |
544 | if ((dp = dp->di_prev) == &dhead) | 545 | if ((dp = dp->di_prev) == &dhead) | |
545 | dp = dp->di_prev; | 546 | dp = dp->di_prev; | |
546 | if (dp == dcwd) | 547 | if (dp == dcwd) | |
547 | stderror(ERR_NAME | ERR_DEEP); | 548 | stderror(ERR_NAME | ERR_DEEP); | |
548 | } | 549 | } | |
549 | return (dp); | 550 | return (dp); | |
550 | } | 551 | } | |
551 | 552 | |||
552 | /* | 553 | /* | |
553 | * dopopd - pop a directory out of the directory stack | 554 | * dopopd - pop a directory out of the directory stack | |
554 | * with a numeric argument just discard it. | 555 | * with a numeric argument just discard it. | |
555 | */ | 556 | */ | |
556 | void | 557 | void | |
557 | /*ARGSUSED*/ | 558 | /*ARGSUSED*/ | |
558 | dopopd(Char **v, struct command *t) | 559 | dopopd(Char **v, struct command *t) | |
559 | { | 560 | { | |
560 | struct directory *dp, *p = NULL; | 561 | struct directory *dp, *p = NULL; | |
561 | 562 | |||
562 | skipargs(&v, " [+<n>]"); | 563 | skipargs(&v, " [+<n>]"); | |
563 | printd = 1; | 564 | printd = 1; | |
564 | if (*v == NULL) | 565 | if (*v == NULL) | |
565 | dp = dcwd; | 566 | dp = dcwd; | |
566 | else if (v[1] != NULL) | 567 | else if (v[1] != NULL) | |
567 | stderror(ERR_NAME | ERR_TOOMANY); | 568 | stderror(ERR_NAME | ERR_TOOMANY); | |
568 | else if ((dp = dfind(*v)) == 0) | 569 | else if ((dp = dfind(*v)) == 0) | |
569 | stderror(ERR_NAME | ERR_BADDIR); | 570 | stderror(ERR_NAME | ERR_BADDIR); | |
570 | if (dp->di_prev == &dhead && dp->di_next == &dhead) | 571 | if (dp->di_prev == &dhead && dp->di_next == &dhead) | |
571 | stderror(ERR_NAME | ERR_EMPTY); | 572 | stderror(ERR_NAME | ERR_EMPTY); | |
572 | if (dp == dcwd) { | 573 | if (dp == dcwd) { | |
573 | char *tmp; | 574 | char *tmp; | |
574 | 575 | |||
575 | if ((p = dp->di_prev) == &dhead) | 576 | if ((p = dp->di_prev) == &dhead) | |
576 | p = dhead.di_prev; | 577 | p = dhead.di_prev; | |
577 | if (chdir(tmp = short2str(p->di_name)) < 0) | 578 | if (chdir(tmp = short2str(p->di_name)) < 0) | |
578 | stderror(ERR_SYSTEM, tmp, strerror(errno)); | 579 | stderror(ERR_SYSTEM, tmp, strerror(errno)); | |
579 | } | 580 | } | |
580 | dp->di_prev->di_next = dp->di_next; | 581 | dp->di_prev->di_next = dp->di_next; | |
581 | dp->di_next->di_prev = dp->di_prev; | 582 | dp->di_next->di_prev = dp->di_prev; | |
582 | if (dp == dcwd) | 583 | if (dp == dcwd) | |
583 | dnewcwd(p); | 584 | dnewcwd(p); | |
584 | else { | 585 | else { | |
585 | printdirs(); | 586 | printdirs(); | |
586 | } | 587 | } | |
587 | dfree(dp); | 588 | dfree(dp); | |
588 | } | 589 | } | |
589 | 590 | |||
590 | /* | 591 | /* | |
591 | * dfree - free the directory (or keep it if it still has ref count) | 592 | * dfree - free the directory (or keep it if it still has ref count) | |
592 | */ | 593 | */ | |
593 | void | 594 | void | |
594 | dfree(struct directory *dp) | 595 | dfree(struct directory *dp) | |
595 | { | 596 | { | |
596 | 597 | |||
597 | if (dp->di_count != 0) { | 598 | if (dp->di_count != 0) { | |
598 | dp->di_next = dp->di_prev = 0; | 599 | dp->di_next = dp->di_prev = 0; | |
599 | } | 600 | } | |
600 | else { | 601 | else { | |
601 | free(dp->di_name); | 602 | free(dp->di_name); | |
602 | free(dp); | 603 | free(dp); | |
603 | } | 604 | } | |
604 | } | 605 | } | |
605 | 606 | |||
606 | /* | 607 | /* | |
607 | * dcanon - canonicalize the pathname, removing excess ./ and ../ etc. | 608 | * dcanon - canonicalize the pathname, removing excess ./ and ../ etc. | |
608 | * we are of course assuming that the file system is standardly | 609 | * we are of course assuming that the file system is standardly | |
609 | * constructed (always have ..'s, directories have links) | 610 | * constructed (always have ..'s, directories have links) | |
610 | */ | 611 | */ | |
611 | Char * | 612 | Char * | |
612 | dcanon(Char *cp, Char *p) | 613 | dcanon(Char *cp, Char *p) | |
613 | { | 614 | { | |
614 | Char slink[MAXPATHLEN]; | 615 | Char slink[MAXPATHLEN]; | |
615 | char tlink[MAXPATHLEN]; | 616 | char tlink[MAXPATHLEN]; | |
616 | Char *newcp, *sp; | 617 | Char *newcp, *sp; | |
617 | Char *p1, *p2; /* general purpose */ | 618 | Char *p1, *p2; /* general purpose */ | |
618 | ssize_t cc; | 619 | ssize_t cc; | |
619 | size_t len; | 620 | size_t len; | |
620 | int slash; | 621 | int slash; | |
621 | 622 | |||
622 | /* | 623 | /* | |
623 | * christos: if the path given does not start with a slash prepend cwd. If | 624 | * christos: if the path given does not start with a slash prepend cwd. If | |
624 | * cwd does not start with a path or the result would be too long abort(). | 625 | * cwd does not start with a path or the result would be too long abort(). | |
625 | */ | 626 | */ | |
626 | if (*cp != '/') { | 627 | if (*cp != '/') { | |
627 | Char tmpdir[MAXPATHLEN]; | 628 | Char tmpdir[MAXPATHLEN]; | |
628 | 629 | |||
629 | p1 = value(STRcwd); | 630 | p1 = value(STRcwd); | |
630 | if (p1 == NULL || *p1 != '/') | 631 | if (p1 == NULL || *p1 != '/') | |
631 | abort(); | 632 | abort(); | |
632 | if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN) | 633 | if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN) | |
633 | abort(); | 634 | abort(); | |
634 | (void)Strcpy(tmpdir, p1); | 635 | (void)Strcpy(tmpdir, p1); | |
635 | (void)Strcat(tmpdir, STRslash); | 636 | (void)Strcat(tmpdir, STRslash); | |
636 | (void)Strcat(tmpdir, cp); | 637 | (void)Strcat(tmpdir, cp); | |
637 | free(cp); | 638 | free(cp); | |
638 | cp = p = Strsave(tmpdir); | 639 | cp = p = Strsave(tmpdir); | |
639 | } | 640 | } | |
640 | 641 | |||
641 | while (*p) { /* for each component */ | 642 | while (*p) { /* for each component */ | |
642 | sp = p; /* save slash address */ | 643 | sp = p; /* save slash address */ | |
643 | while (*++p == '/') /* flush extra slashes */ | 644 | while (*++p == '/') /* flush extra slashes */ | |
644 | continue; | 645 | continue; | |
645 | if (p != ++sp) | 646 | if (p != ++sp) | |
646 | for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';) | 647 | for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';) | |
647 | continue; | 648 | continue; | |
648 | p = sp; /* save start of component */ | 649 | p = sp; /* save start of component */ | |
649 | slash = 0; | 650 | slash = 0; | |
650 | while (*++p) /* find next slash or end of path */ | 651 | while (*++p) /* find next slash or end of path */ | |
651 | if (*p == '/') { | 652 | if (*p == '/') { | |
652 | slash = 1; | 653 | slash = 1; | |
653 | *p = 0; | 654 | *p = 0; | |
654 | break; | 655 | break; | |
655 | } | 656 | } | |
656 | 657 | |||
657 | if (*sp == '\0') { /* if component is null */ | 658 | if (*sp == '\0') { /* if component is null */ | |
658 | if (--sp == cp) /* if path is one char (i.e. /) */ | 659 | if (--sp == cp) /* if path is one char (i.e. /) */ | |
659 | break; | 660 | break; | |
660 | else | 661 | else | |
661 | *sp = '\0'; | 662 | *sp = '\0'; | |
662 | } else if (sp[0] == '.' && sp[1] == 0) { | 663 | } else if (sp[0] == '.' && sp[1] == 0) { | |
663 | if (slash) { | 664 | if (slash) { | |
664 | for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';) | 665 | for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';) | |
665 | continue; | 666 | continue; | |
666 | p = --sp; | 667 | p = --sp; | |
667 | } | 668 | } | |
668 | else if (--sp != cp) | 669 | else if (--sp != cp) | |
669 | *sp = '\0'; | 670 | *sp = '\0'; | |
670 | } | 671 | } | |
671 | else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) { | 672 | else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) { | |
672 | /* | 673 | /* | |
673 | * We have something like "yyy/xxx/..", where "yyy" can be null or | 674 | * We have something like "yyy/xxx/..", where "yyy" can be null or | |
674 | * a path starting at /, and "xxx" is a single component. Before | 675 | * a path starting at /, and "xxx" is a single component. Before | |
675 | * compressing "xxx/..", we want to expand "yyy/xxx", if it is a | 676 | * compressing "xxx/..", we want to expand "yyy/xxx", if it is a | |
676 | * symbolic link. | 677 | * symbolic link. | |
677 | */ | 678 | */ | |
678 | *--sp = 0; /* form the pathname for readlink */ | 679 | *--sp = 0; /* form the pathname for readlink */ | |
679 | if (sp != cp && !adrof(STRignore_symlinks) && | 680 | if (sp != cp && !adrof(STRignore_symlinks) && | |
680 | (cc = readlink(short2str(cp), tlink, | 681 | (cc = readlink(short2str(cp), tlink, | |
681 | sizeof(tlink) - 1)) >= 0) { | 682 | sizeof(tlink) - 1)) >= 0) { | |
682 | tlink[cc] = '\0'; | 683 | tlink[cc] = '\0'; | |
683 | (void)Strcpy(slink, str2short(tlink)); | 684 | (void)Strcpy(slink, str2short(tlink)); | |
684 | 685 | |||
685 | if (slash) | 686 | if (slash) | |
686 | *p = '/'; | 687 | *p = '/'; | |
687 | /* | 688 | /* | |
688 | * Point p to the '/' in "/..", and restore the '/'. | 689 | * Point p to the '/' in "/..", and restore the '/'. | |
689 | */ | 690 | */ | |
690 | *(p = sp) = '/'; | 691 | *(p = sp) = '/'; | |
691 | /* | 692 | /* | |
692 | * find length of p | 693 | * find length of p | |
693 | */ | 694 | */ | |
694 | for (p1 = p; *p1++;) | 695 | for (p1 = p; *p1++;) | |
695 | continue; | 696 | continue; | |
696 | if (*slink != '/') { | 697 | if (*slink != '/') { | |
697 | /* | 698 | /* | |
698 | * Relative path, expand it between the "yyy/" and the | 699 | * Relative path, expand it between the "yyy/" and the | |
699 | * "/..". First, back sp up to the character past "yyy/". | 700 | * "/..". First, back sp up to the character past "yyy/". | |
700 | */ | 701 | */ | |
701 | while (*--sp != '/') | 702 | while (*--sp != '/') | |
702 | continue; | 703 | continue; | |
703 | sp++; | 704 | sp++; | |
704 | *sp = 0; | 705 | *sp = 0; | |
705 | /* | 706 | /* | |
706 | * New length is "yyy/" + slink + "/.." and rest | 707 | * New length is "yyy/" + slink + "/.." and rest | |
707 | */ | 708 | */ | |
708 | p1 = newcp = xmalloc( | 709 | p1 = newcp = xreallocarray(NULL, | |
709 | (size_t)((sp - cp) + cc + (p1 - p)) * sizeof(Char)); | 710 | (size_t)((sp - cp) + cc + (p1 - p)), sizeof(Char)); | |
710 | /* | 711 | /* | |
711 | * Copy new path into newcp | 712 | * Copy new path into newcp | |
712 | */ | 713 | */ | |
713 | for (p2 = cp; (*p1++ = *p2++) != '\0';) | 714 | for (p2 = cp; (*p1++ = *p2++) != '\0';) | |
714 | continue; | 715 | continue; | |
715 | for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';) | 716 | for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';) | |
716 | continue; | 717 | continue; | |
717 | for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) | 718 | for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) | |
718 | continue; | 719 | continue; | |
719 | /* | 720 | /* | |
720 | * Restart canonicalization at expanded "/xxx". | 721 | * Restart canonicalization at expanded "/xxx". | |
721 | */ | 722 | */ | |
722 | p = sp - cp - 1 + newcp; | 723 | p = sp - cp - 1 + newcp; | |
723 | } | 724 | } | |
724 | else { | 725 | else { | |
725 | /* | 726 | /* | |
726 | * New length is slink + "/.." and rest | 727 | * New length is slink + "/.." and rest | |
727 | */ | 728 | */ | |
728 | p1 = newcp = xmalloc( | 729 | p1 = newcp = xreallocarray(NULL, | |
729 | (size_t)(cc + (p1 - p)) * sizeof(Char)); | 730 | (size_t)(cc + (p1 - p)), sizeof(Char)); | |
730 | /* | 731 | /* | |
731 | * Copy new path into newcp | 732 | * Copy new path into newcp | |
732 | */ | 733 | */ | |
733 | for (p2 = slink; (*p1++ = *p2++) != '\0';) | 734 | for (p2 = slink; (*p1++ = *p2++) != '\0';) | |
734 | continue; | 735 | continue; | |
735 | for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) | 736 | for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) | |
736 | continue; | 737 | continue; | |
737 | /* | 738 | /* | |
738 | * Restart canonicalization at beginning | 739 | * Restart canonicalization at beginning | |
739 | */ | 740 | */ | |
740 | p = newcp; | 741 | p = newcp; | |
741 | } | 742 | } | |
742 | free(cp); | 743 | free(cp); | |
743 | cp = newcp; | 744 | cp = newcp; | |
744 | continue; /* canonicalize the link */ | 745 | continue; /* canonicalize the link */ | |
745 | } | 746 | } | |
746 | *sp = '/'; | 747 | *sp = '/'; | |
747 | if (sp != cp) | 748 | if (sp != cp) | |
748 | while (*--sp != '/') | 749 | while (*--sp != '/') | |
749 | continue; | 750 | continue; | |
750 | if (slash) { | 751 | if (slash) { | |
751 | for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';) | 752 | for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';) | |
752 | continue; | 753 | continue; | |
753 | p = sp; | 754 | p = sp; | |
754 | } | 755 | } | |
755 | else if (cp == sp) | 756 | else if (cp == sp) | |
756 | *++sp = '\0'; | 757 | *++sp = '\0'; | |
757 | else | 758 | else | |
758 | *sp = '\0'; | 759 | *sp = '\0'; | |
759 | } | 760 | } | |
760 | else { /* normal dir name (not . or .. or nothing) */ | 761 | else { /* normal dir name (not . or .. or nothing) */ | |
761 | 762 | |||
762 | if (sp != cp && adrof(STRchase_symlinks) && | 763 | if (sp != cp && adrof(STRchase_symlinks) && | |
763 | !adrof(STRignore_symlinks) && | 764 | !adrof(STRignore_symlinks) && | |
764 | (cc = readlink(short2str(cp), tlink, sizeof(tlink)-1)) >= 0) { | 765 | (cc = readlink(short2str(cp), tlink, sizeof(tlink)-1)) >= 0) { | |
765 | tlink[cc] = '\0'; | 766 | tlink[cc] = '\0'; | |
766 | (void)Strcpy(slink, str2short(tlink)); | 767 | (void)Strcpy(slink, str2short(tlink)); | |
767 | 768 | |||
768 | /* | 769 | /* | |
769 | * restore the '/'. | 770 | * restore the '/'. | |
770 | */ | 771 | */ | |
771 | if (slash) | 772 | if (slash) | |
772 | *p = '/'; | 773 | *p = '/'; | |
773 | 774 | |||
774 | /* | 775 | /* | |
775 | * point sp to p (rather than backing up). | 776 | * point sp to p (rather than backing up). | |
776 | */ | 777 | */ | |
777 | sp = p; | 778 | sp = p; | |
778 | 779 | |||
779 | /* | 780 | /* | |
780 | * find length of p | 781 | * find length of p | |
781 | */ | 782 | */ | |
782 | for (p1 = p; *p1++;) | 783 | for (p1 = p; *p1++;) | |
783 | continue; | 784 | continue; | |
784 | if (*slink != '/') { | 785 | if (*slink != '/') { | |
785 | /* | 786 | /* | |
786 | * Relative path, expand it between the "yyy/" and the | 787 | * Relative path, expand it between the "yyy/" and the | |
787 | * remainder. First, back sp up to the character past | 788 | * remainder. First, back sp up to the character past | |
788 | * "yyy/". | 789 | * "yyy/". | |
789 | */ | 790 | */ | |
790 | while (*--sp != '/') | 791 | while (*--sp != '/') | |
791 | continue; | 792 | continue; | |
792 | sp++; | 793 | sp++; | |
793 | *sp = 0; | 794 | *sp = 0; | |
794 | /* | 795 | /* | |
795 | * New length is "yyy/" + slink + "/.." and rest | 796 | * New length is "yyy/" + slink + "/.." and rest | |
796 | */ | 797 | */ | |
797 | p1 = newcp = xmalloc( | 798 | p1 = newcp = xreallocarray(NULL, | |
798 | (size_t)((sp - cp) + cc + (p1 - p)) * sizeof(Char)); | 799 | (size_t)((sp - cp) + cc + (p1 - p)), sizeof(Char)); | |
799 | /* | 800 | /* | |
800 | * Copy new path into newcp | 801 | * Copy new path into newcp | |
801 | */ | 802 | */ | |
802 | for (p2 = cp; (*p1++ = *p2++) != '\0';) | 803 | for (p2 = cp; (*p1++ = *p2++) != '\0';) | |
803 | continue; | 804 | continue; | |
804 | for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';) | 805 | for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';) | |
805 | continue; | 806 | continue; | |
806 | for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) | 807 | for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) | |
807 | continue; | 808 | continue; | |
808 | /* | 809 | /* | |
809 | * Restart canonicalization at expanded "/xxx". | 810 | * Restart canonicalization at expanded "/xxx". | |
810 | */ | 811 | */ | |
811 | p = sp - cp - 1 + newcp; | 812 | p = sp - cp - 1 + newcp; | |
812 | } | 813 | } | |
813 | else { | 814 | else { | |
814 | /* | 815 | /* | |
815 | * New length is slink + the rest | 816 | * New length is slink + the rest | |
816 | */ | 817 | */ | |
817 | p1 = newcp = xmalloc( | 818 | p1 = newcp = xreallocarray(NULL, | |
818 | (size_t)(cc + (p1 - p)) * sizeof(Char)); | 819 | (size_t)(cc + (p1 - p)), sizeof(Char)); | |
819 | /* | 820 | /* | |
820 | * Copy new path into newcp | 821 | * Copy new path into newcp | |
821 | */ | 822 | */ | |
822 | for (p2 = slink; (*p1++ = *p2++) != '\0';) | 823 | for (p2 = slink; (*p1++ = *p2++) != '\0';) | |
823 | continue; | 824 | continue; | |
824 | for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) | 825 | for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) | |
825 | continue; | 826 | continue; | |
826 | /* | 827 | /* | |
827 | * Restart canonicalization at beginning | 828 | * Restart canonicalization at beginning | |
828 | */ | 829 | */ | |
829 | p = newcp; | 830 | p = newcp; | |
830 | } | 831 | } | |
831 | free(cp); | 832 | free(cp); | |
832 | cp = newcp; | 833 | cp = newcp; | |
833 | continue; /* canonicalize the link */ | 834 | continue; /* canonicalize the link */ | |
834 | } | 835 | } | |
835 | if (slash) | 836 | if (slash) | |
836 | *p = '/'; | 837 | *p = '/'; | |
837 | } | 838 | } | |
838 | } | 839 | } | |
839 | 840 | |||
840 | /* | 841 | /* | |
841 | * fix home... | 842 | * fix home... | |
842 | */ | 843 | */ | |
843 | p1 = value(STRhome); | 844 | p1 = value(STRhome); | |
844 | len = Strlen(p1); | 845 | len = Strlen(p1); | |
845 | /* | 846 | /* | |
846 | * See if we're not in a subdir of STRhome | 847 | * See if we're not in a subdir of STRhome | |
847 | */ | 848 | */ | |
848 | if (p1 && *p1 == '/' && | 849 | if (p1 && *p1 == '/' && | |
849 | (Strncmp(p1, cp, len) != 0 || (cp[len] != '/' && cp[len] != '\0'))) { | 850 | (Strncmp(p1, cp, len) != 0 || (cp[len] != '/' && cp[len] != '\0'))) { | |
850 | static ino_t home_ino; | 851 | static ino_t home_ino; | |
851 | static dev_t home_dev = NODEV; | 852 | static dev_t home_dev = NODEV; | |
852 | static Char *home_ptr = NULL; | 853 | static Char *home_ptr = NULL; | |
853 | struct stat statbuf; | 854 | struct stat statbuf; | |
854 | 855 | |||
855 | /* | 856 | /* | |
856 | * Get dev and ino of STRhome | 857 | * Get dev and ino of STRhome | |
857 | */ | 858 | */ | |
858 | if (home_ptr != p1 && | 859 | if (home_ptr != p1 && | |
859 | stat(short2str(p1), &statbuf) != -1) { | 860 | stat(short2str(p1), &statbuf) != -1) { | |
860 | home_dev = statbuf.st_dev; | 861 | home_dev = statbuf.st_dev; | |
861 | home_ino = statbuf.st_ino; | 862 | home_ino = statbuf.st_ino; | |
862 | home_ptr = p1; | 863 | home_ptr = p1; | |
863 | } | 864 | } | |
864 | /* | 865 | /* | |
865 | * Start comparing dev & ino backwards | 866 | * Start comparing dev & ino backwards | |
866 | */ | 867 | */ | |
867 | p2 = Strcpy(slink, cp); | 868 | p2 = Strcpy(slink, cp); | |
868 | for (sp = NULL; *p2 && stat(short2str(p2), &statbuf) != -1;) { | 869 | for (sp = NULL; *p2 && stat(short2str(p2), &statbuf) != -1;) { | |
869 | if (statbuf.st_dev == home_dev && | 870 | if (statbuf.st_dev == home_dev && | |
870 | statbuf.st_ino == home_ino) { | 871 | statbuf.st_ino == home_ino) { | |
871 | sp = (Char *) - 1; | 872 | sp = (Char *) - 1; | |
872 | break; | 873 | break; | |
873 | } | 874 | } | |
874 | if ((sp = Strrchr(p2, '/')) != NULL) | 875 | if ((sp = Strrchr(p2, '/')) != NULL) | |
875 | *sp = '\0'; | 876 | *sp = '\0'; | |
876 | } | 877 | } | |
877 | /* | 878 | /* | |
878 | * See if we found it | 879 | * See if we found it | |
879 | */ | 880 | */ | |
880 | if (*p2 && sp == (Char *) -1) { | 881 | if (*p2 && sp == (Char *) -1) { | |
881 | /* | 882 | /* | |
882 | * Use STRhome to make '~' work | 883 | * Use STRhome to make '~' work | |
883 | */ | 884 | */ | |
884 | newcp = Strspl(p1, cp + Strlen(p2)); | 885 | newcp = Strspl(p1, cp + Strlen(p2)); | |
885 | free(cp); | 886 | free(cp); | |
886 | cp = newcp; | 887 | cp = newcp; | |
887 | } | 888 | } | |
888 | } | 889 | } | |
889 | return cp; | 890 | return cp; | |
890 | } | 891 | } | |
891 | 892 | |||
892 | 893 | |||
893 | /* | 894 | /* | |
894 | * dnewcwd - make a new directory in the loop the current one | 895 | * dnewcwd - make a new directory in the loop the current one | |
895 | */ | 896 | */ | |
896 | static void | 897 | static void | |
897 | dnewcwd(struct directory *dp) | 898 | dnewcwd(struct directory *dp) | |
898 | { | 899 | { | |
899 | dcwd = dp; | 900 | dcwd = dp; | |
900 | dset(dcwd->di_name); | 901 | dset(dcwd->di_name); | |
901 | if (printd && !(adrof(STRpushdsilent))) | 902 | if (printd && !(adrof(STRpushdsilent))) | |
902 | printdirs(); | 903 | printdirs(); | |
903 | } | 904 | } |
--- src/bin/csh/file.c 2020/09/29 02:58:51 1.33
+++ src/bin/csh/file.c 2024/04/24 15:49:03 1.34
@@ -1,728 +1,725 @@ | @@ -1,728 +1,725 @@ | |||
1 | /* $NetBSD: file.c,v 1.33 2020/09/29 02:58:51 msaitoh Exp $ */ | 1 | /* $NetBSD: file.c,v 1.34 2024/04/24 15:49:03 nia Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1980, 1991, 1993 | 4 | * Copyright (c) 1980, 1991, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the University nor the names of its contributors | 15 | * 3. Neither the name of the University nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | #if 0 | 34 | #if 0 | |
35 | static char sccsid[] = "@(#)file.c 8.2 (Berkeley) 3/19/94"; | 35 | static char sccsid[] = "@(#)file.c 8.2 (Berkeley) 3/19/94"; | |
36 | #else | 36 | #else | |
37 | __RCSID("$NetBSD: file.c,v 1.33 2020/09/29 02:58:51 msaitoh Exp $"); | 37 | __RCSID("$NetBSD: file.c,v 1.34 2024/04/24 15:49:03 nia Exp $"); | |
38 | #endif | 38 | #endif | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #ifdef FILEC | 41 | #ifdef FILEC | |
42 | 42 | |||
43 | #include <sys/ioctl.h> | 43 | #include <sys/ioctl.h> | |
44 | #include <sys/param.h> | 44 | #include <sys/param.h> | |
45 | #include <sys/stat.h> | 45 | #include <sys/stat.h> | |
46 | #include <sys/tty.h> | 46 | #include <sys/tty.h> | |
47 | 47 | |||
48 | #include <dirent.h> | 48 | #include <dirent.h> | |
49 | #include <pwd.h> | 49 | #include <pwd.h> | |
50 | #include <termios.h> | 50 | #include <termios.h> | |
51 | #include <stdarg.h> | 51 | #include <stdarg.h> | |
52 | #include <stdlib.h> | 52 | #include <stdlib.h> | |
53 | #include <unistd.h> | 53 | #include <unistd.h> | |
54 | 54 | |||
55 | #ifndef SHORT_STRINGS | 55 | #ifndef SHORT_STRINGS | |
56 | #include <string.h> | 56 | #include <string.h> | |
57 | #endif /* SHORT_STRINGS */ | 57 | #endif /* SHORT_STRINGS */ | |
58 | 58 | |||
59 | #include "csh.h" | 59 | #include "csh.h" | |
60 | #include "extern.h" | 60 | #include "extern.h" | |
61 | 61 | |||
62 | /* | 62 | /* | |
63 | * Tenex style file name recognition, .. and more. | 63 | * Tenex style file name recognition, .. and more. | |
64 | * History: | 64 | * History: | |
65 | * Author: Ken Greer, Sept. 1975, CMU. | 65 | * Author: Ken Greer, Sept. 1975, CMU. | |
66 | * Finally got around to adding to the Cshell., Ken Greer, Dec. 1981. | 66 | * Finally got around to adding to the Cshell., Ken Greer, Dec. 1981. | |
67 | */ | 67 | */ | |
68 | 68 | |||
69 | #define ON 1 | 69 | #define ON 1 | |
70 | #define OFF 0 | 70 | #define OFF 0 | |
71 | #ifndef TRUE | 71 | #ifndef TRUE | |
72 | #define TRUE 1 | 72 | #define TRUE 1 | |
73 | #endif | 73 | #endif | |
74 | #ifndef FALSE | 74 | #ifndef FALSE | |
75 | #define FALSE 0 | 75 | #define FALSE 0 | |
76 | #endif | 76 | #endif | |
77 | 77 | |||
78 | #define ESC '\033' | 78 | #define ESC '\033' | |
79 | 79 | |||
80 | typedef enum { | 80 | typedef enum { | |
81 | LIST, RECOGNIZE | 81 | LIST, RECOGNIZE | |
82 | } COMMAND; | 82 | } COMMAND; | |
83 | 83 | |||
84 | static void setup_tty(int); | 84 | static void setup_tty(int); | |
85 | static void back_to_col_1(void); | 85 | static void back_to_col_1(void); | |
86 | static int pushback(Char *); | 86 | static int pushback(Char *); | |
87 | static void catn(Char *, Char *, size_t); | 87 | static void catn(Char *, Char *, size_t); | |
88 | static void copyn(Char *, Char *, size_t); | 88 | static void copyn(Char *, Char *, size_t); | |
89 | static Char filetype(Char *, Char *); | 89 | static Char filetype(Char *, Char *); | |
90 | static void print_by_column(Char *, Char *[], size_t); | 90 | static void print_by_column(Char *, Char *[], size_t); | |
91 | static Char *tilde(Char *, Char *); | 91 | static Char *tilde(Char *, Char *); | |
92 | static void retype(void); | 92 | static void retype(void); | |
93 | static void beep(void); | 93 | static void beep(void); | |
94 | static void print_recognized_stuff(Char *); | 94 | static void print_recognized_stuff(Char *); | |
95 | static void extract_dir_and_name(Char *, Char *, Char *); | 95 | static void extract_dir_and_name(Char *, Char *, Char *); | |
96 | static Char *getentry(DIR *, int); | 96 | static Char *getentry(DIR *, int); | |
97 | static void free_items(Char **, size_t); | 97 | static void free_items(Char **, size_t); | |
98 | static size_t tsearch(Char *, COMMAND, size_t); | 98 | static size_t tsearch(Char *, COMMAND, size_t); | |
99 | static int recognize(Char *, Char *, size_t, size_t); | 99 | static int recognize(Char *, Char *, size_t, size_t); | |
100 | static int is_prefix(Char *, Char *); | 100 | static int is_prefix(Char *, Char *); | |
101 | static int is_suffix(Char *, Char *); | 101 | static int is_suffix(Char *, Char *); | |
102 | static int ignored(Char *); | 102 | static int ignored(Char *); | |
103 | 103 | |||
104 | /* | 104 | /* | |
105 | * Put this here so the binary can be patched with adb to enable file | 105 | * Put this here so the binary can be patched with adb to enable file | |
106 | * completion by default. Filec controls completion, nobeep controls | 106 | * completion by default. Filec controls completion, nobeep controls | |
107 | * ringing the terminal bell on incomplete expansions. | 107 | * ringing the terminal bell on incomplete expansions. | |
108 | */ | 108 | */ | |
109 | int filec = 0; | 109 | int filec = 0; | |
110 | 110 | |||
111 | static void | 111 | static void | |
112 | setup_tty(int on) | 112 | setup_tty(int on) | |
113 | { | 113 | { | |
114 | struct termios tchars; | 114 | struct termios tchars; | |
115 | 115 | |||
116 | (void)tcgetattr(SHIN, &tchars); | 116 | (void)tcgetattr(SHIN, &tchars); | |
117 | 117 | |||
118 | if (on) { | 118 | if (on) { | |
119 | tchars.c_cc[VEOL] = ESC; | 119 | tchars.c_cc[VEOL] = ESC; | |
120 | if (tchars.c_lflag & ICANON) | 120 | if (tchars.c_lflag & ICANON) | |
121 | on = TCSADRAIN; | 121 | on = TCSADRAIN; | |
122 | else { | 122 | else { | |
123 | tchars.c_lflag |= ICANON; | 123 | tchars.c_lflag |= ICANON; | |
124 | on = TCSAFLUSH; | 124 | on = TCSAFLUSH; | |
125 | } | 125 | } | |
126 | } | 126 | } | |
127 | else { | 127 | else { | |
128 | tchars.c_cc[VEOL] = _POSIX_VDISABLE; | 128 | tchars.c_cc[VEOL] = _POSIX_VDISABLE; | |
129 | on = TCSADRAIN; | 129 | on = TCSADRAIN; | |
130 | } | 130 | } | |
131 | 131 | |||
132 | (void)tcsetattr(SHIN, on, &tchars); | 132 | (void)tcsetattr(SHIN, on, &tchars); | |
133 | } | 133 | } | |
134 | 134 | |||
135 | /* | 135 | /* | |
136 | * Move back to beginning of current line | 136 | * Move back to beginning of current line | |
137 | */ | 137 | */ | |
138 | static void | 138 | static void | |
139 | back_to_col_1(void) | 139 | back_to_col_1(void) | |
140 | { | 140 | { | |
141 | struct termios tty, tty_normal; | 141 | struct termios tty, tty_normal; | |
142 | sigset_t nsigset, osigset; | 142 | sigset_t nsigset, osigset; | |
143 | 143 | |||
144 | sigemptyset(&nsigset); | 144 | sigemptyset(&nsigset); | |
145 | (void)sigaddset(&nsigset, SIGINT); | 145 | (void)sigaddset(&nsigset, SIGINT); | |
146 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); | 146 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); | |
147 | (void)tcgetattr(SHOUT, &tty); | 147 | (void)tcgetattr(SHOUT, &tty); | |
148 | tty_normal = tty; | 148 | tty_normal = tty; | |
149 | tty.c_iflag &= ~INLCR; | 149 | tty.c_iflag &= ~INLCR; | |
150 | tty.c_oflag &= ~ONLCR; | 150 | tty.c_oflag &= ~ONLCR; | |
151 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty); | 151 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty); | |
152 | (void)write(SHOUT, "\r", 1); | 152 | (void)write(SHOUT, "\r", 1); | |
153 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty_normal); | 153 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty_normal); | |
154 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); | 154 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); | |
155 | } | 155 | } | |
156 | 156 | |||
157 | /* | 157 | /* | |
158 | * Push string contents back into tty queue | 158 | * Push string contents back into tty queue | |
159 | */ | 159 | */ | |
160 | static int | 160 | static int | |
161 | pushback(Char *string) | 161 | pushback(Char *string) | |
162 | { | 162 | { | |
163 | struct termios tty, tty_normal; | 163 | struct termios tty, tty_normal; | |
164 | char buf[64], svchars[sizeof(buf)]; | 164 | char buf[64], svchars[sizeof(buf)]; | |
165 | sigset_t nsigset, osigset; | 165 | sigset_t nsigset, osigset; | |
166 | Char *p; | 166 | Char *p; | |
167 | size_t bufidx, i, len_str, nbuf, nsv, onsv, retrycnt; | 167 | size_t bufidx, i, len_str, nbuf, nsv, onsv, retrycnt; | |
168 | char c; | 168 | char c; | |
169 | 169 | |||
170 | nsv = 0; | 170 | nsv = 0; | |
171 | sigemptyset(&nsigset); | 171 | sigemptyset(&nsigset); | |
172 | (void)sigaddset(&nsigset, SIGINT); | 172 | (void)sigaddset(&nsigset, SIGINT); | |
173 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); | 173 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); | |
174 | (void)tcgetattr(SHOUT, &tty); | 174 | (void)tcgetattr(SHOUT, &tty); | |
175 | tty_normal = tty; | 175 | tty_normal = tty; | |
176 | tty.c_lflag &= ~(ECHOKE | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOCTL); | 176 | tty.c_lflag &= ~(ECHOKE | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOCTL); | |
177 | /* FIONREAD works only in noncanonical mode. */ | 177 | /* FIONREAD works only in noncanonical mode. */ | |
178 | tty.c_lflag &= ~ICANON; | 178 | tty.c_lflag &= ~ICANON; | |
179 | tty.c_cc[VMIN] = 0; | 179 | tty.c_cc[VMIN] = 0; | |
180 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty); | 180 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty); | |
181 | 181 | |||
182 | for (retrycnt = 5; ; retrycnt--) { | 182 | for (retrycnt = 5; ; retrycnt--) { | |
183 | /* | 183 | /* | |
184 | * Push back characters. | 184 | * Push back characters. | |
185 | */ | 185 | */ | |
186 | for (p = string; (c = (char)*p) != '\0'; p++) | 186 | for (p = string; (c = (char)*p) != '\0'; p++) | |
187 | (void)ioctl(SHOUT, TIOCSTI, (ioctl_t) &c); | 187 | (void)ioctl(SHOUT, TIOCSTI, (ioctl_t) &c); | |
188 | for (i = 0; i < nsv; i++) | 188 | for (i = 0; i < nsv; i++) | |
189 | (void)ioctl(SHOUT, TIOCSTI, (ioctl_t) &svchars[i]); | 189 | (void)ioctl(SHOUT, TIOCSTI, (ioctl_t) &svchars[i]); | |
190 | 190 | |||
191 | if (retrycnt == 0) | 191 | if (retrycnt == 0) | |
192 | break; /* give up salvaging characters */ | 192 | break; /* give up salvaging characters */ | |
193 | 193 | |||
194 | len_str = (size_t)(p - string); | 194 | len_str = (size_t)(p - string); | |
195 | 195 | |||
196 | if (ioctl(SHOUT, FIONREAD, (ioctl_t) &nbuf) || | 196 | if (ioctl(SHOUT, FIONREAD, (ioctl_t) &nbuf) || | |
197 | nbuf <= len_str + nsv || /* The string fit. */ | 197 | nbuf <= len_str + nsv || /* The string fit. */ | |
198 | nbuf > sizeof(buf)) /* For future binary compatibility | 198 | nbuf > sizeof(buf)) /* For future binary compatibility | |
199 | (and safety). */ | 199 | (and safety). */ | |
200 | break; | 200 | break; | |
201 | 201 | |||
202 | /* | 202 | /* | |
203 | * User has typed characters before the pushback finished. | 203 | * User has typed characters before the pushback finished. | |
204 | * Salvage the characters. | 204 | * Salvage the characters. | |
205 | */ | 205 | */ | |
206 | 206 | |||
207 | /* This read() should be in noncanonical mode. */ | 207 | /* This read() should be in noncanonical mode. */ | |
208 | if (read(SHOUT, &buf, nbuf) != (ssize_t)nbuf) | 208 | if (read(SHOUT, &buf, nbuf) != (ssize_t)nbuf) | |
209 | continue; /* hangup? */ | 209 | continue; /* hangup? */ | |
210 | 210 | |||
211 | onsv = nsv; | 211 | onsv = nsv; | |
212 | for (bufidx = 0, i = 0; bufidx < nbuf; bufidx++, i++) { | 212 | for (bufidx = 0, i = 0; bufidx < nbuf; bufidx++, i++) { | |
213 | c = buf[bufidx]; | 213 | c = buf[bufidx]; | |
214 | if ((i < len_str) ? c != (char)string[i] : | 214 | if ((i < len_str) ? c != (char)string[i] : | |
215 | (i < len_str + onsv) ? c != svchars[i - len_str] : 1) { | 215 | (i < len_str + onsv) ? c != svchars[i - len_str] : 1) { | |
216 | /* Salvage a character. */ | 216 | /* Salvage a character. */ | |
217 | if (nsv < (int)(sizeof svchars / sizeof svchars[0])) { | 217 | if (nsv < (int)(sizeof svchars / sizeof svchars[0])) { | |
218 | svchars[nsv++] = c; | 218 | svchars[nsv++] = c; | |
219 | i--; /* try this comparison with the next char */ | 219 | i--; /* try this comparison with the next char */ | |
220 | } else | 220 | } else | |
221 | break; /* too many */ | 221 | break; /* too many */ | |
222 | } | 222 | } | |
223 | } | 223 | } | |
224 | } | 224 | } | |
225 | 225 | |||
226 | #if 1 | 226 | #if 1 | |
227 | /* | 227 | /* | |
228 | * XXX Is this a bug or a feature of kernel tty driver? | 228 | * XXX Is this a bug or a feature of kernel tty driver? | |
229 | * | 229 | * | |
230 | * FIONREAD in canonical mode does not return correct byte count | 230 | * FIONREAD in canonical mode does not return correct byte count | |
231 | * in tty input queue, but this is required to avoid unwanted echo. | 231 | * in tty input queue, but this is required to avoid unwanted echo. | |
232 | */ | 232 | */ | |
233 | tty.c_lflag |= ICANON; | 233 | tty.c_lflag |= ICANON; | |
234 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty); | 234 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty); | |
235 | (void)ioctl(SHOUT, FIONREAD, (ioctl_t) &i); | 235 | (void)ioctl(SHOUT, FIONREAD, (ioctl_t) &i); | |
236 | #endif | 236 | #endif | |
237 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty_normal); | 237 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty_normal); | |
238 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); | 238 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); | |
239 | 239 | |||
240 | return (int)nsv; | 240 | return (int)nsv; | |
241 | } | 241 | } | |
242 | 242 | |||
243 | /* | 243 | /* | |
244 | * Concatenate src onto tail of des. | 244 | * Concatenate src onto tail of des. | |
245 | * Des is a string whose maximum length is count. | 245 | * Des is a string whose maximum length is count. | |
246 | * Always null terminate. | 246 | * Always null terminate. | |
247 | */ | 247 | */ | |
248 | static void | 248 | static void | |
249 | catn(Char *des, Char *src, size_t count) | 249 | catn(Char *des, Char *src, size_t count) | |
250 | { | 250 | { | |
251 | while (count-- > 0 && *des) | 251 | while (count-- > 0 && *des) | |
252 | des++; | 252 | des++; | |
253 | while (count-- > 0) | 253 | while (count-- > 0) | |
254 | if ((*des++ = *src++) == 0) | 254 | if ((*des++ = *src++) == 0) | |
255 | return; | 255 | return; | |
256 | *des = '\0'; | 256 | *des = '\0'; | |
257 | } | 257 | } | |
258 | 258 | |||
259 | /* | 259 | /* | |
260 | * Like strncpy but always leave room for trailing \0 | 260 | * Like strncpy but always leave room for trailing \0 | |
261 | * and always null terminate. | 261 | * and always null terminate. | |
262 | */ | 262 | */ | |
263 | static void | 263 | static void | |
264 | copyn(Char *des, Char *src, size_t count) | 264 | copyn(Char *des, Char *src, size_t count) | |
265 | { | 265 | { | |
266 | while (count-- > 0) | 266 | while (count-- > 0) | |
267 | if ((*des++ = *src++) == 0) | 267 | if ((*des++ = *src++) == 0) | |
268 | return; | 268 | return; | |
269 | *des = '\0'; | 269 | *des = '\0'; | |
270 | } | 270 | } | |
271 | 271 | |||
272 | static Char | 272 | static Char | |
273 | filetype(Char *dir, Char *file) | 273 | filetype(Char *dir, Char *file) | |
274 | { | 274 | { | |
275 | struct stat statb; | 275 | struct stat statb; | |
276 | Char path[MAXPATHLEN]; | 276 | Char path[MAXPATHLEN]; | |
277 | 277 | |||
278 | catn(Strcpy(path, dir), file, sizeof(path) / sizeof(Char)); | 278 | catn(Strcpy(path, dir), file, sizeof(path) / sizeof(Char)); | |
279 | if (lstat(short2str(path), &statb) == 0) { | 279 | if (lstat(short2str(path), &statb) == 0) { | |
280 | switch (statb.st_mode & S_IFMT) { | 280 | switch (statb.st_mode & S_IFMT) { | |
281 | case S_IFDIR: | 281 | case S_IFDIR: | |
282 | return ('/'); | 282 | return ('/'); | |
283 | case S_IFLNK: | 283 | case S_IFLNK: | |
284 | if (stat(short2str(path), &statb) == 0 && /* follow it out */ | 284 | if (stat(short2str(path), &statb) == 0 && /* follow it out */ | |
285 | S_ISDIR(statb.st_mode)) | 285 | S_ISDIR(statb.st_mode)) | |
286 | return ('>'); | 286 | return ('>'); | |
287 | else | 287 | else | |
288 | return ('@'); | 288 | return ('@'); | |
289 | case S_IFSOCK: | 289 | case S_IFSOCK: | |
290 | return ('='); | 290 | return ('='); | |
291 | default: | 291 | default: | |
292 | if (statb.st_mode & 0111) | 292 | if (statb.st_mode & 0111) | |
293 | return ('*'); | 293 | return ('*'); | |
294 | } | 294 | } | |
295 | } | 295 | } | |
296 | return (' '); | 296 | return (' '); | |
297 | } | 297 | } | |
298 | 298 | |||
299 | static struct winsize win; | 299 | static struct winsize win; | |
300 | 300 | |||
301 | /* | 301 | /* | |
302 | * Print sorted down columns | 302 | * Print sorted down columns | |
303 | */ | 303 | */ | |
304 | static void | 304 | static void | |
305 | print_by_column(Char *dir, Char *items[], size_t count) | 305 | print_by_column(Char *dir, Char *items[], size_t count) | |
306 | { | 306 | { | |
307 | size_t c, columns, i, maxwidth, r, rows; | 307 | size_t c, columns, i, maxwidth, r, rows; | |
308 | 308 | |||
309 | maxwidth = 0; | 309 | maxwidth = 0; | |
310 | 310 | |||
311 | if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & win) < 0 || win.ws_col == 0) | 311 | if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & win) < 0 || win.ws_col == 0) | |
312 | win.ws_col = 80; | 312 | win.ws_col = 80; | |
313 | for (i = 0; i < count; i++) | 313 | for (i = 0; i < count; i++) | |
314 | maxwidth = maxwidth > (r = Strlen(items[i])) ? maxwidth : r; | 314 | maxwidth = maxwidth > (r = Strlen(items[i])) ? maxwidth : r; | |
315 | maxwidth += 2; /* for the file tag and space */ | 315 | maxwidth += 2; /* for the file tag and space */ | |
316 | columns = win.ws_col / maxwidth; | 316 | columns = win.ws_col / maxwidth; | |
317 | if (columns == 0) | 317 | if (columns == 0) | |
318 | columns = 1; | 318 | columns = 1; | |
319 | rows = (count + (columns - 1)) / columns; | 319 | rows = (count + (columns - 1)) / columns; | |
320 | for (r = 0; r < rows; r++) { | 320 | for (r = 0; r < rows; r++) { | |
321 | for (c = 0; c < columns; c++) { | 321 | for (c = 0; c < columns; c++) { | |
322 | i = c * rows + r; | 322 | i = c * rows + r; | |
323 | if (i < count) { | 323 | if (i < count) { | |
324 | size_t w; | 324 | size_t w; | |
325 | 325 | |||
326 | (void)fprintf(cshout, "%s", vis_str(items[i])); | 326 | (void)fprintf(cshout, "%s", vis_str(items[i])); | |
327 | (void)fputc(dir ? filetype(dir, items[i]) : ' ', cshout); | 327 | (void)fputc(dir ? filetype(dir, items[i]) : ' ', cshout); | |
328 | if (c < columns - 1) { /* last column? */ | 328 | if (c < columns - 1) { /* last column? */ | |
329 | w = Strlen(items[i]) + 1; | 329 | w = Strlen(items[i]) + 1; | |
330 | for (; w < maxwidth; w++) | 330 | for (; w < maxwidth; w++) | |
331 | (void) fputc(' ', cshout); | 331 | (void) fputc(' ', cshout); | |
332 | } | 332 | } | |
333 | } | 333 | } | |
334 | } | 334 | } | |
335 | (void)fputc('\r', cshout); | 335 | (void)fputc('\r', cshout); | |
336 | (void)fputc('\n', cshout); | 336 | (void)fputc('\n', cshout); | |
337 | } | 337 | } | |
338 | } | 338 | } | |
339 | 339 | |||
340 | /* | 340 | /* | |
341 | * Expand file name with possible tilde usage | 341 | * Expand file name with possible tilde usage | |
342 | * ~person/mumble | 342 | * ~person/mumble | |
343 | * expands to | 343 | * expands to | |
344 | * home_directory_of_person/mumble | 344 | * home_directory_of_person/mumble | |
345 | */ | 345 | */ | |
346 | static Char * | 346 | static Char * | |
347 | tilde(Char *new, Char *old) | 347 | tilde(Char *new, Char *old) | |
348 | { | 348 | { | |
349 | static Char person[40]; | 349 | static Char person[40]; | |
350 | struct passwd *pw; | 350 | struct passwd *pw; | |
351 | Char *o, *p; | 351 | Char *o, *p; | |
352 | 352 | |||
353 | if (old[0] != '~') | 353 | if (old[0] != '~') | |
354 | return (Strcpy(new, old)); | 354 | return (Strcpy(new, old)); | |
355 | 355 | |||
356 | for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++) | 356 | for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++) | |
357 | continue; | 357 | continue; | |
358 | *p = '\0'; | 358 | *p = '\0'; | |
359 | if (person[0] == '\0') | 359 | if (person[0] == '\0') | |
360 | (void)Strcpy(new, value(STRhome)); | 360 | (void)Strcpy(new, value(STRhome)); | |
361 | else { | 361 | else { | |
362 | pw = getpwnam(short2str(person)); | 362 | pw = getpwnam(short2str(person)); | |
363 | if (pw == NULL) | 363 | if (pw == NULL) | |
364 | return (NULL); | 364 | return (NULL); | |
365 | (void)Strcpy(new, str2short(pw->pw_dir)); | 365 | (void)Strcpy(new, str2short(pw->pw_dir)); | |
366 | } | 366 | } | |
367 | (void)Strcat(new, o); | 367 | (void)Strcat(new, o); | |
368 | return (new); | 368 | return (new); | |
369 | } | 369 | } | |
370 | 370 | |||
371 | /* | 371 | /* | |
372 | * Cause pending line to be printed | 372 | * Cause pending line to be printed | |
373 | */ | 373 | */ | |
374 | static void | 374 | static void | |
375 | retype(void) | 375 | retype(void) | |
376 | { | 376 | { | |
377 | struct termios tty; | 377 | struct termios tty; | |
378 | 378 | |||
379 | (void)tcgetattr(SHOUT, &tty); | 379 | (void)tcgetattr(SHOUT, &tty); | |
380 | tty.c_lflag |= PENDIN; | 380 | tty.c_lflag |= PENDIN; | |
381 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty); | 381 | (void)tcsetattr(SHOUT, TCSADRAIN, &tty); | |
382 | } | 382 | } | |
383 | 383 | |||
384 | static void | 384 | static void | |
385 | beep(void) | 385 | beep(void) | |
386 | { | 386 | { | |
387 | if (adrof(STRnobeep) == 0) | 387 | if (adrof(STRnobeep) == 0) | |
388 | (void)write(SHOUT, "\007", 1); | 388 | (void)write(SHOUT, "\007", 1); | |
389 | } | 389 | } | |
390 | 390 | |||
391 | /* | 391 | /* | |
392 | * Erase that silly ^[ and | 392 | * Erase that silly ^[ and | |
393 | * print the recognized part of the string | 393 | * print the recognized part of the string | |
394 | */ | 394 | */ | |
395 | static void | 395 | static void | |
396 | print_recognized_stuff(Char *recognized_part) | 396 | print_recognized_stuff(Char *recognized_part) | |
397 | { | 397 | { | |
398 | /* An optimized erasing of that silly ^[ */ | 398 | /* An optimized erasing of that silly ^[ */ | |
399 | (void)fputc('\b', cshout); | 399 | (void)fputc('\b', cshout); | |
400 | (void)fputc('\b', cshout); | 400 | (void)fputc('\b', cshout); | |
401 | switch (Strlen(recognized_part)) { | 401 | switch (Strlen(recognized_part)) { | |
402 | case 0: /* erase two Characters: ^[ */ | 402 | case 0: /* erase two Characters: ^[ */ | |
403 | (void)fputc(' ', cshout); | 403 | (void)fputc(' ', cshout); | |
404 | (void)fputc(' ', cshout); | 404 | (void)fputc(' ', cshout); | |
405 | (void)fputc('\b', cshout); | 405 | (void)fputc('\b', cshout); | |
406 | (void)fputc('\b', cshout); | 406 | (void)fputc('\b', cshout); | |
407 | break; | 407 | break; | |
408 | case 1: /* overstrike the ^, erase the [ */ | 408 | case 1: /* overstrike the ^, erase the [ */ | |
409 | (void)fprintf(cshout, "%s", vis_str(recognized_part)); | 409 | (void)fprintf(cshout, "%s", vis_str(recognized_part)); | |
410 | (void)fputc(' ', cshout); | 410 | (void)fputc(' ', cshout); | |
411 | (void)fputc('\b', cshout); | 411 | (void)fputc('\b', cshout); | |
412 | break; | 412 | break; | |
413 | default: /* overstrike both Characters ^[ */ | 413 | default: /* overstrike both Characters ^[ */ | |
414 | (void)fprintf(cshout, "%s", vis_str(recognized_part)); | 414 | (void)fprintf(cshout, "%s", vis_str(recognized_part)); | |
415 | break; | 415 | break; | |
416 | } | 416 | } | |
417 | (void)fflush(cshout); | 417 | (void)fflush(cshout); | |
418 | } | 418 | } | |
419 | 419 | |||
420 | /* | 420 | /* | |
421 | * Parse full path in file into 2 parts: directory and file names | 421 | * Parse full path in file into 2 parts: directory and file names | |
422 | * Should leave final slash (/) at end of dir. | 422 | * Should leave final slash (/) at end of dir. | |
423 | */ | 423 | */ | |
424 | static void | 424 | static void | |
425 | extract_dir_and_name(Char *path, Char *dir, Char *name) | 425 | extract_dir_and_name(Char *path, Char *dir, Char *name) | |
426 | { | 426 | { | |
427 | Char *p; | 427 | Char *p; | |
428 | 428 | |||
429 | p = Strrchr(path, '/'); | 429 | p = Strrchr(path, '/'); | |
430 | if (p == NULL) { | 430 | if (p == NULL) { | |
431 | copyn(name, path, MAXNAMLEN); | 431 | copyn(name, path, MAXNAMLEN); | |
432 | dir[0] = '\0'; | 432 | dir[0] = '\0'; | |
433 | } | 433 | } | |
434 | else { | 434 | else { | |
435 | copyn(name, ++p, MAXNAMLEN); | 435 | copyn(name, ++p, MAXNAMLEN); | |
436 | copyn(dir, path, (size_t)(p - path)); | 436 | copyn(dir, path, (size_t)(p - path)); | |
437 | } | 437 | } | |
438 | } | 438 | } | |
439 | 439 | |||
440 | static Char * | 440 | static Char * | |
441 | getentry(DIR *dir_fd, int looking_for_lognames) | 441 | getentry(DIR *dir_fd, int looking_for_lognames) | |
442 | { | 442 | { | |
443 | struct dirent *dirp; | 443 | struct dirent *dirp; | |
444 | struct passwd *pw; | 444 | struct passwd *pw; | |
445 | 445 | |||
446 | if (looking_for_lognames) { | 446 | if (looking_for_lognames) { | |
447 | if ((pw = getpwent()) == NULL) | 447 | if ((pw = getpwent()) == NULL) | |
448 | return (NULL); | 448 | return (NULL); | |
449 | return (str2short(pw->pw_name)); | 449 | return (str2short(pw->pw_name)); | |
450 | } | 450 | } | |
451 | if ((dirp = readdir(dir_fd)) != NULL) | 451 | if ((dirp = readdir(dir_fd)) != NULL) | |
452 | return (str2short(dirp->d_name)); | 452 | return (str2short(dirp->d_name)); | |
453 | return (NULL); | 453 | return (NULL); | |
454 | } | 454 | } | |
455 | 455 | |||
456 | static void | 456 | static void | |
457 | free_items(Char **items, size_t numitems) | 457 | free_items(Char **items, size_t numitems) | |
458 | { | 458 | { | |
459 | size_t i; | 459 | size_t i; | |
460 | 460 | |||
461 | for (i = 0; i < numitems; i++) | 461 | for (i = 0; i < numitems; i++) | |
462 | free(items[i]); | 462 | free(items[i]); | |
463 | free(items); | 463 | free(items); | |
464 | } | 464 | } | |
465 | 465 | |||
466 | #define FREE_ITEMS(items, numitems) { \ | 466 | #define FREE_ITEMS(items, numitems) { \ | |
467 | sigset_t nsigset, osigset;\ | 467 | sigset_t nsigset, osigset;\ | |
468 | \ | 468 | \ | |
469 | sigemptyset(&nsigset);\ | 469 | sigemptyset(&nsigset);\ | |
470 | (void) sigaddset(&nsigset, SIGINT);\ | 470 | (void) sigaddset(&nsigset, SIGINT);\ | |
471 | (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);\ | 471 | (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);\ | |
472 | free_items(items, numitems);\ | 472 | free_items(items, numitems);\ | |
473 | (void) sigprocmask(SIG_SETMASK, &osigset, NULL);\ | 473 | (void) sigprocmask(SIG_SETMASK, &osigset, NULL);\ | |
474 | } | 474 | } | |
475 | 475 | |||
476 | /* | 476 | /* | |
477 | * Perform a RECOGNIZE or LIST command on string "word". | 477 | * Perform a RECOGNIZE or LIST command on string "word". | |
478 | */ | 478 | */ | |
479 | static size_t | 479 | static size_t | |
480 | tsearch(Char *word, COMMAND command, size_t max_word_length) | 480 | tsearch(Char *word, COMMAND command, size_t max_word_length) | |
481 | { | 481 | { | |
482 | Char dir[MAXPATHLEN + 1], extended_name[MAXNAMLEN + 1]; | 482 | Char dir[MAXPATHLEN + 1], extended_name[MAXNAMLEN + 1]; | |
483 | Char name[MAXNAMLEN + 1], tilded_dir[MAXPATHLEN + 1]; | 483 | Char name[MAXNAMLEN + 1], tilded_dir[MAXPATHLEN + 1]; | |
484 | DIR *dir_fd; | 484 | DIR *dir_fd; | |
485 | Char *entry; | 485 | Char *entry; | |
486 | int ignoring, looking_for_lognames; | 486 | int ignoring, looking_for_lognames; | |
487 | size_t name_length, nignored, numitems; | 487 | size_t name_length, nignored, numitems; | |
488 | Char **items = NULL; | 488 | Char **items = NULL; | |
489 | size_t maxitems = 0; | 489 | size_t maxitems = 0; | |
490 | 490 | |||
491 | numitems = 0; | 491 | numitems = 0; | |
492 | ignoring = TRUE; | 492 | ignoring = TRUE; | |
493 | nignored = 0; | 493 | nignored = 0; | |
494 | 494 | |||
495 | looking_for_lognames = (*word == '~') && (Strchr(word, '/') == NULL); | 495 | looking_for_lognames = (*word == '~') && (Strchr(word, '/') == NULL); | |
496 | if (looking_for_lognames) { | 496 | if (looking_for_lognames) { | |
497 | (void)setpwent(); | 497 | (void)setpwent(); | |
498 | copyn(name, &word[1], MAXNAMLEN); /* name sans ~ */ | 498 | copyn(name, &word[1], MAXNAMLEN); /* name sans ~ */ | |
499 | dir_fd = NULL; | 499 | dir_fd = NULL; | |
500 | } | 500 | } | |
501 | else { | 501 | else { | |
502 | extract_dir_and_name(word, dir, name); | 502 | extract_dir_and_name(word, dir, name); | |
503 | if (tilde(tilded_dir, dir) == 0) | 503 | if (tilde(tilded_dir, dir) == 0) | |
504 | return (0); | 504 | return (0); | |
505 | dir_fd = opendir(*tilded_dir ? short2str(tilded_dir) : "."); | 505 | dir_fd = opendir(*tilded_dir ? short2str(tilded_dir) : "."); | |
506 | if (dir_fd == NULL) | 506 | if (dir_fd == NULL) | |
507 | return (0); | 507 | return (0); | |
508 | } | 508 | } | |
509 | 509 | |||
510 | again: /* search for matches */ | 510 | again: /* search for matches */ | |
511 | name_length = Strlen(name); | 511 | name_length = Strlen(name); | |
512 | for (numitems = 0; (entry = getentry(dir_fd, looking_for_lognames)) != NULL;) { | 512 | for (numitems = 0; (entry = getentry(dir_fd, looking_for_lognames)) != NULL;) { | |
513 | if (!is_prefix(name, entry)) | 513 | if (!is_prefix(name, entry)) | |
514 | continue; | 514 | continue; | |
515 | /* Don't match . files on null prefix match */ | 515 | /* Don't match . files on null prefix match */ | |
516 | if (name_length == 0 && entry[0] == '.' && | 516 | if (name_length == 0 && entry[0] == '.' && | |
517 | !looking_for_lognames) | 517 | !looking_for_lognames) | |
518 | continue; | 518 | continue; | |
519 | if (command == LIST) { | 519 | if (command == LIST) { | |
520 | if ((size_t)numitems >= maxitems) { | 520 | if ((size_t)numitems >= maxitems) { | |
521 | maxitems += 1024; | 521 | maxitems += 1024; | |
522 | if (items == NULL) | 522 | items = xreallocarray(items, sizeof(*items), maxitems); | |
523 | items = xmalloc(sizeof(*items) * maxitems); | |||
524 | else | |||
525 | items = xrealloc(items, sizeof(*items) * maxitems); | |||
526 | } | 523 | } | |
527 | items[numitems] = xmalloc((size_t) (Strlen(entry) + 1) * | 524 | items[numitems] = xreallocarray(NULL, | |
528 | sizeof(Char)); | 525 | (size_t) (Strlen(entry) + 1), sizeof(Char)); | |
529 | copyn(items[numitems], entry, MAXNAMLEN); | 526 | copyn(items[numitems], entry, MAXNAMLEN); | |
530 | numitems++; | 527 | numitems++; | |
531 | } | 528 | } | |
532 | else { /* RECOGNIZE command */ | 529 | else { /* RECOGNIZE command */ | |
533 | if (ignoring && ignored(entry)) | 530 | if (ignoring && ignored(entry)) | |
534 | nignored++; | 531 | nignored++; | |
535 | else if (recognize(extended_name, | 532 | else if (recognize(extended_name, | |
536 | entry, name_length, ++numitems)) | 533 | entry, name_length, ++numitems)) | |
537 | break; | 534 | break; | |
538 | } | 535 | } | |
539 | } | 536 | } | |
540 | if (ignoring && numitems == 0 && nignored > 0) { | 537 | if (ignoring && numitems == 0 && nignored > 0) { | |
541 | ignoring = FALSE; | 538 | ignoring = FALSE; | |
542 | nignored = 0; | 539 | nignored = 0; | |
543 | if (looking_for_lognames) | 540 | if (looking_for_lognames) | |
544 | (void)setpwent(); | 541 | (void)setpwent(); | |
545 | else | 542 | else | |
546 | rewinddir(dir_fd); | 543 | rewinddir(dir_fd); | |
547 | goto again; | 544 | goto again; | |
548 | } | 545 | } | |
549 | 546 | |||
550 | if (looking_for_lognames) | 547 | if (looking_for_lognames) | |
551 | (void)endpwent(); | 548 | (void)endpwent(); | |
552 | else | 549 | else | |
553 | (void)closedir(dir_fd); | 550 | (void)closedir(dir_fd); | |
554 | if (numitems == 0) | 551 | if (numitems == 0) | |
555 | return (0); | 552 | return (0); | |
556 | if (command == RECOGNIZE) { | 553 | if (command == RECOGNIZE) { | |
557 | if (looking_for_lognames) | 554 | if (looking_for_lognames) | |
558 | copyn(word, STRtilde, 1); | 555 | copyn(word, STRtilde, 1); | |
559 | else | 556 | else | |
560 | /* put back dir part */ | 557 | /* put back dir part */ | |
561 | copyn(word, dir, max_word_length); | 558 | copyn(word, dir, max_word_length); | |
562 | /* add extended name */ | 559 | /* add extended name */ | |
563 | catn(word, extended_name, max_word_length); | 560 | catn(word, extended_name, max_word_length); | |
564 | return (numitems); | 561 | return (numitems); | |
565 | } | 562 | } | |
566 | else { /* LIST */ | 563 | else { /* LIST */ | |
567 | qsort(items, numitems, sizeof(items[0]), | 564 | qsort(items, numitems, sizeof(items[0]), | |
568 | (int (*) (const void *, const void *)) sortscmp); | 565 | (int (*) (const void *, const void *)) sortscmp); | |
569 | print_by_column(looking_for_lognames ? NULL : tilded_dir, | 566 | print_by_column(looking_for_lognames ? NULL : tilded_dir, | |
570 | items, numitems); | 567 | items, numitems); | |
571 | if (items != NULL) | 568 | if (items != NULL) | |
572 | FREE_ITEMS(items, numitems); | 569 | FREE_ITEMS(items, numitems); | |
573 | } | 570 | } | |
574 | return (0); | 571 | return (0); | |
575 | } | 572 | } | |
576 | 573 | |||
577 | /* | 574 | /* | |
578 | * Object: extend what user typed up to an ambiguity. | 575 | * Object: extend what user typed up to an ambiguity. | |
579 | * Algorithm: | 576 | * Algorithm: | |
580 | * On first match, copy full entry (assume it'll be the only match) | 577 | * On first match, copy full entry (assume it'll be the only match) | |
581 | * On subsequent matches, shorten extended_name to the first | 578 | * On subsequent matches, shorten extended_name to the first | |
582 | * Character mismatch between extended_name and entry. | 579 | * Character mismatch between extended_name and entry. | |
583 | * If we shorten it back to the prefix length, stop searching. | 580 | * If we shorten it back to the prefix length, stop searching. | |
584 | */ | 581 | */ | |
585 | static int | 582 | static int | |
586 | recognize(Char *extended_name, Char *entry, size_t name_length, size_t numitems) | 583 | recognize(Char *extended_name, Char *entry, size_t name_length, size_t numitems) | |
587 | { | 584 | { | |
588 | if (numitems == 1) /* 1st match */ | 585 | if (numitems == 1) /* 1st match */ | |
589 | copyn(extended_name, entry, MAXNAMLEN); | 586 | copyn(extended_name, entry, MAXNAMLEN); | |
590 | else { /* 2nd & subsequent matches */ | 587 | else { /* 2nd & subsequent matches */ | |
591 | Char *ent, *x; | 588 | Char *ent, *x; | |
592 | size_t len = 0; | 589 | size_t len = 0; | |
593 | 590 | |||
594 | x = extended_name; | 591 | x = extended_name; | |
595 | for (ent = entry; *x && *x == *ent++; x++, len++) | 592 | for (ent = entry; *x && *x == *ent++; x++, len++) | |
596 | continue; | 593 | continue; | |
597 | *x = '\0'; /* Shorten at 1st Char diff */ | 594 | *x = '\0'; /* Shorten at 1st Char diff */ | |
598 | if (len == name_length) /* Ambiguous to prefix? */ | 595 | if (len == name_length) /* Ambiguous to prefix? */ | |
599 | return (-1); /* So stop now and save time */ | 596 | return (-1); /* So stop now and save time */ | |
600 | } | 597 | } | |
601 | return (0); | 598 | return (0); | |
602 | } | 599 | } | |
603 | 600 | |||
604 | /* | 601 | /* | |
605 | * Return true if check matches initial Chars in template. | 602 | * Return true if check matches initial Chars in template. | |
606 | * This differs from PWB imatch in that if check is null | 603 | * This differs from PWB imatch in that if check is null | |
607 | * it matches anything. | 604 | * it matches anything. | |
608 | */ | 605 | */ | |
609 | static int | 606 | static int | |
610 | is_prefix(Char *check, Char *template) | 607 | is_prefix(Char *check, Char *template) | |
611 | { | 608 | { | |
612 | do | 609 | do | |
613 | if (*check == 0) | 610 | if (*check == 0) | |
614 | return (TRUE); | 611 | return (TRUE); | |
615 | while (*check++ == *template++); | 612 | while (*check++ == *template++); | |
616 | return (FALSE); | 613 | return (FALSE); | |
617 | } | 614 | } | |
618 | 615 | |||
619 | /* | 616 | /* | |
620 | * Return true if the Chars in template appear at the | 617 | * Return true if the Chars in template appear at the | |
621 | * end of check, I.e., are its suffix. | 618 | * end of check, I.e., are its suffix. | |
622 | */ | 619 | */ | |
623 | static int | 620 | static int | |
624 | is_suffix(Char *check, Char *template) | 621 | is_suffix(Char *check, Char *template) | |
625 | { | 622 | { | |
626 | Char *c, *t; | 623 | Char *c, *t; | |
627 | 624 | |||
628 | for (c = check; *c++;) | 625 | for (c = check; *c++;) | |
629 | continue; | 626 | continue; | |
630 | for (t = template; *t++;) | 627 | for (t = template; *t++;) | |
631 | continue; | 628 | continue; | |
632 | for (;;) { | 629 | for (;;) { | |
633 | if (t == template) | 630 | if (t == template) | |
634 | return 1; | 631 | return 1; | |
635 | if (c == check || *--t != *--c) | 632 | if (c == check || *--t != *--c) | |
636 | return 0; | 633 | return 0; | |
637 | } | 634 | } | |
638 | } | 635 | } | |
639 | 636 | |||
640 | ssize_t | 637 | ssize_t | |
641 | tenex(Char *inputline, size_t inputline_size) | 638 | tenex(Char *inputline, size_t inputline_size) | |
642 | { | 639 | { | |
643 | char tinputline[BUFSIZE]; | 640 | char tinputline[BUFSIZE]; | |
644 | ssize_t num_read; | 641 | ssize_t num_read; | |
645 | size_t numitems; | 642 | size_t numitems; | |
646 | 643 | |||
647 | setup_tty(ON); | 644 | setup_tty(ON); | |
648 | 645 | |||
649 | while ((num_read = read(SHIN, tinputline, BUFSIZE)) > 0) { | 646 | while ((num_read = read(SHIN, tinputline, BUFSIZE)) > 0) { | |
650 | size_t i, nr = (size_t) num_read; | 647 | size_t i, nr = (size_t) num_read; | |
651 | 648 | |||
652 | 649 | |||
653 | static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<', | 650 | static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<', | |
654 | '>', '(', ')', '|', '^', '%', '\0'}; | 651 | '>', '(', ')', '|', '^', '%', '\0'}; | |
655 | Char *str_end, *word_start, last_Char, should_retype; | 652 | Char *str_end, *word_start, last_Char, should_retype; | |
656 | size_t space_left; | 653 | size_t space_left; | |
657 | COMMAND command; | 654 | COMMAND command; | |
658 | 655 | |||
659 | for (i = 0; i < nr; i++) | 656 | for (i = 0; i < nr; i++) | |
660 | inputline[i] = (unsigned char) tinputline[i]; | 657 | inputline[i] = (unsigned char) tinputline[i]; | |
661 | last_Char = inputline[nr - 1] & ASCII; | 658 | last_Char = inputline[nr - 1] & ASCII; | |
662 | 659 | |||
663 | if (last_Char == '\n' || nr == inputline_size) | 660 | if (last_Char == '\n' || nr == inputline_size) | |
664 | break; | 661 | break; | |
665 | command = (last_Char == ESC) ? RECOGNIZE : LIST; | 662 | command = (last_Char == ESC) ? RECOGNIZE : LIST; | |
666 | if (command == LIST) | 663 | if (command == LIST) | |
667 | (void)fputc('\n', cshout); | 664 | (void)fputc('\n', cshout); | |
668 | str_end = &inputline[nr]; | 665 | str_end = &inputline[nr]; | |
669 | if (last_Char == ESC) | 666 | if (last_Char == ESC) | |
670 | --str_end; /* wipeout trailing cmd Char */ | 667 | --str_end; /* wipeout trailing cmd Char */ | |
671 | *str_end = '\0'; | 668 | *str_end = '\0'; | |
672 | /* | 669 | /* | |
673 | * Find LAST occurrence of a delimiter in the inputline. The word start | 670 | * Find LAST occurrence of a delimiter in the inputline. The word start | |
674 | * is one Character past it. | 671 | * is one Character past it. | |
675 | */ | 672 | */ | |
676 | for (word_start = str_end; word_start > inputline; --word_start) | 673 | for (word_start = str_end; word_start > inputline; --word_start) | |
677 | if (Strchr(delims, word_start[-1])) | 674 | if (Strchr(delims, word_start[-1])) | |
678 | break; | 675 | break; | |
679 | space_left = inputline_size - (size_t)(word_start - inputline) - 1; | 676 | space_left = inputline_size - (size_t)(word_start - inputline) - 1; | |
680 | numitems = tsearch(word_start, command, space_left); | 677 | numitems = tsearch(word_start, command, space_left); | |
681 | 678 | |||
682 | if (command == RECOGNIZE) { | 679 | if (command == RECOGNIZE) { | |
683 | /* print from str_end on */ | 680 | /* print from str_end on */ | |
684 | print_recognized_stuff(str_end); | 681 | print_recognized_stuff(str_end); | |
685 | if (numitems != 1) /* Beep = No match/ambiguous */ | 682 | if (numitems != 1) /* Beep = No match/ambiguous */ | |
686 | beep(); | 683 | beep(); | |
687 | } | 684 | } | |
688 | 685 | |||
689 | /* | 686 | /* | |
690 | * Tabs in the input line cause trouble after a pushback. tty driver | 687 | * Tabs in the input line cause trouble after a pushback. tty driver | |
691 | * won't backspace over them because column positions are now | 688 | * won't backspace over them because column positions are now | |
692 | * incorrect. This is solved by retyping over current line. | 689 | * incorrect. This is solved by retyping over current line. | |
693 | */ | 690 | */ | |
694 | should_retype = FALSE; | 691 | should_retype = FALSE; | |
695 | if (Strchr(inputline, '\t')) { /* tab Char in input line? */ | 692 | if (Strchr(inputline, '\t')) { /* tab Char in input line? */ | |
696 | back_to_col_1(); | 693 | back_to_col_1(); | |
697 | should_retype = TRUE; | 694 | should_retype = TRUE; | |
698 | } | 695 | } | |
699 | if (command == LIST) /* Always retype after a LIST */ | 696 | if (command == LIST) /* Always retype after a LIST */ | |
700 | should_retype = TRUE; | 697 | should_retype = TRUE; | |
701 | if (pushback(inputline)) | 698 | if (pushback(inputline)) | |
702 | should_retype = TRUE; | 699 | should_retype = TRUE; | |
703 | if (should_retype) { | 700 | if (should_retype) { | |
704 | if (command == RECOGNIZE) | 701 | if (command == RECOGNIZE) | |
705 | (void) fputc('\n', cshout); | 702 | (void) fputc('\n', cshout); | |
706 | printprompt(); | 703 | printprompt(); | |
707 | } | 704 | } | |
708 | if (should_retype) | 705 | if (should_retype) | |
709 | retype(); | 706 | retype(); | |
710 | } | 707 | } | |
711 | setup_tty(OFF); | 708 | setup_tty(OFF); | |
712 | return num_read; | 709 | return num_read; | |
713 | } | 710 | } | |
714 | 711 | |||
715 | static int | 712 | static int | |
716 | ignored(Char *entry) | 713 | ignored(Char *entry) | |
717 | { | 714 | { | |
718 | struct varent *vp; | 715 | struct varent *vp; | |
719 | Char **cp; | 716 | Char **cp; | |
720 | 717 | |||
721 | if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL) | 718 | if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL) | |
722 | return (FALSE); | 719 | return (FALSE); | |
723 | for (; *cp != NULL; cp++) | 720 | for (; *cp != NULL; cp++) | |
724 | if (is_suffix(entry, *cp)) | 721 | if (is_suffix(entry, *cp)) | |
725 | return (TRUE); | 722 | return (TRUE); | |
726 | return (FALSE); | 723 | return (FALSE); | |
727 | } | 724 | } | |
728 | #endif /* FILEC */ | 725 | #endif /* FILEC */ |
--- src/bin/csh/func.c 2020/08/09 00:22:53 1.44
+++ src/bin/csh/func.c 2024/04/24 15:49:03 1.45
@@ -1,1456 +1,1456 @@ | @@ -1,1456 +1,1456 @@ | |||
1 | /* $NetBSD: func.c,v 1.44 2020/08/09 00:22:53 dholland Exp $ */ | 1 | /* $NetBSD: func.c,v 1.45 2024/04/24 15:49:03 nia Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1980, 1991, 1993 | 4 | * Copyright (c) 1980, 1991, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the University nor the names of its contributors | 15 | * 3. Neither the name of the University nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | #if 0 | 34 | #if 0 | |
35 | static char sccsid[] = "@(#)func.c 8.1 (Berkeley) 5/31/93"; | 35 | static char sccsid[] = "@(#)func.c 8.1 (Berkeley) 5/31/93"; | |
36 | #else | 36 | #else | |
37 | __RCSID("$NetBSD: func.c,v 1.44 2020/08/09 00:22:53 dholland Exp $"); | 37 | __RCSID("$NetBSD: func.c,v 1.45 2024/04/24 15:49:03 nia Exp $"); | |
38 | #endif | 38 | #endif | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #include <sys/stat.h> | 41 | #include <sys/stat.h> | |
42 | #include <sys/types.h> | 42 | #include <sys/types.h> | |
43 | 43 | |||
44 | #include <locale.h> | 44 | #include <locale.h> | |
45 | #include <inttypes.h> | 45 | #include <inttypes.h> | |
46 | #include <signal.h> | 46 | #include <signal.h> | |
47 | #include <stdarg.h> | 47 | #include <stdarg.h> | |
48 | #include <stdlib.h> | 48 | #include <stdlib.h> | |
49 | #include <string.h> | 49 | #include <string.h> | |
50 | #include <unistd.h> | 50 | #include <unistd.h> | |
51 | #include <errno.h> | 51 | #include <errno.h> | |
52 | 52 | |||
53 | #include "csh.h" | 53 | #include "csh.h" | |
54 | #include "extern.h" | 54 | #include "extern.h" | |
55 | #include "pathnames.h" | 55 | #include "pathnames.h" | |
56 | 56 | |||
57 | extern char **environ; | 57 | extern char **environ; | |
58 | extern int progprintf(int, char **); | 58 | extern int progprintf(int, char **); | |
59 | 59 | |||
60 | static void islogin(void); | 60 | static void islogin(void); | |
61 | static void reexecute(struct command *); | 61 | static void reexecute(struct command *); | |
62 | static void preread(void); | 62 | static void preread(void); | |
63 | static void doagain(void); | 63 | static void doagain(void); | |
64 | static void search(int, int, Char *); | 64 | static void search(int, int, Char *); | |
65 | static int getword(Char *); | 65 | static int getword(Char *); | |
66 | static int keyword(Char *); | 66 | static int keyword(Char *); | |
67 | static void toend(void); | 67 | static void toend(void); | |
68 | static void xecho(int, Char **); | 68 | static void xecho(int, Char **); | |
69 | static void Unsetenv(Char *); | 69 | static void Unsetenv(Char *); | |
70 | static void wpfree(struct whyle *); | 70 | static void wpfree(struct whyle *); | |
71 | 71 | |||
72 | struct biltins * | 72 | struct biltins * | |
73 | isbfunc(struct command *t) | 73 | isbfunc(struct command *t) | |
74 | { | 74 | { | |
75 | static struct biltins label = {"", dozip, 0, 0}; | 75 | static struct biltins label = {"", dozip, 0, 0}; | |
76 | static struct biltins foregnd = {"%job", dofg1, 0, 0}; | 76 | static struct biltins foregnd = {"%job", dofg1, 0, 0}; | |
77 | static struct biltins backgnd = {"%job &", dobg1, 0, 0}; | 77 | static struct biltins backgnd = {"%job &", dobg1, 0, 0}; | |
78 | struct biltins *bp, *bp1, *bp2; | 78 | struct biltins *bp, *bp1, *bp2; | |
79 | Char *cp; | 79 | Char *cp; | |
80 | 80 | |||
81 | cp = t->t_dcom[0]; | 81 | cp = t->t_dcom[0]; | |
82 | 82 | |||
83 | if (lastchr(cp) == ':') { | 83 | if (lastchr(cp) == ':') { | |
84 | label.bname = short2str(cp); | 84 | label.bname = short2str(cp); | |
85 | return (&label); | 85 | return (&label); | |
86 | } | 86 | } | |
87 | if (*cp == '%') { | 87 | if (*cp == '%') { | |
88 | if (t->t_dflg & F_AMPERSAND) { | 88 | if (t->t_dflg & F_AMPERSAND) { | |
89 | t->t_dflg &= ~F_AMPERSAND; | 89 | t->t_dflg &= ~F_AMPERSAND; | |
90 | backgnd.bname = short2str(cp); | 90 | backgnd.bname = short2str(cp); | |
91 | return (&backgnd); | 91 | return (&backgnd); | |
92 | } | 92 | } | |
93 | foregnd.bname = short2str(cp); | 93 | foregnd.bname = short2str(cp); | |
94 | return (&foregnd); | 94 | return (&foregnd); | |
95 | } | 95 | } | |
96 | /* | 96 | /* | |
97 | * Binary search Bp1 is the beginning of the current search range. Bp2 is | 97 | * Binary search Bp1 is the beginning of the current search range. Bp2 is | |
98 | * one past the end. | 98 | * one past the end. | |
99 | */ | 99 | */ | |
100 | for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { | 100 | for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { | |
101 | int i; | 101 | int i; | |
102 | 102 | |||
103 | bp = bp1 + ((bp2 - bp1) >> 1); | 103 | bp = bp1 + ((bp2 - bp1) >> 1); | |
104 | if ((i = *cp - *bp->bname) == 0 && | 104 | if ((i = *cp - *bp->bname) == 0 && | |
105 | (i = Strcmp(cp, str2short(bp->bname))) == 0) | 105 | (i = Strcmp(cp, str2short(bp->bname))) == 0) | |
106 | return bp; | 106 | return bp; | |
107 | if (i < 0) | 107 | if (i < 0) | |
108 | bp2 = bp; | 108 | bp2 = bp; | |
109 | else | 109 | else | |
110 | bp1 = bp + 1; | 110 | bp1 = bp + 1; | |
111 | } | 111 | } | |
112 | return (0); | 112 | return (0); | |
113 | } | 113 | } | |
114 | 114 | |||
115 | void | 115 | void | |
116 | func(struct command *t, struct biltins *bp) | 116 | func(struct command *t, struct biltins *bp) | |
117 | { | 117 | { | |
118 | int i; | 118 | int i; | |
119 | 119 | |||
120 | xechoit(t->t_dcom); | 120 | xechoit(t->t_dcom); | |
121 | setname(bp->bname); | 121 | setname(bp->bname); | |
122 | i = blklen(t->t_dcom) - 1; | 122 | i = blklen(t->t_dcom) - 1; | |
123 | if (i < bp->minargs) | 123 | if (i < bp->minargs) | |
124 | stderror(ERR_NAME | ERR_TOOFEW); | 124 | stderror(ERR_NAME | ERR_TOOFEW); | |
125 | if (i > bp->maxargs) | 125 | if (i > bp->maxargs) | |
126 | stderror(ERR_NAME | ERR_TOOMANY); | 126 | stderror(ERR_NAME | ERR_TOOMANY); | |
127 | (*bp->bfunct) (t->t_dcom, t); | 127 | (*bp->bfunct) (t->t_dcom, t); | |
128 | } | 128 | } | |
129 | 129 | |||
130 | void | 130 | void | |
131 | /*ARGSUSED*/ | 131 | /*ARGSUSED*/ | |
132 | doonintr(Char **v, struct command *t) | 132 | doonintr(Char **v, struct command *t) | |
133 | { | 133 | { | |
134 | Char *cp, *vv; | 134 | Char *cp, *vv; | |
135 | sigset_t nsigset; | 135 | sigset_t nsigset; | |
136 | 136 | |||
137 | vv = v[1]; | 137 | vv = v[1]; | |
138 | if (parintr == SIG_IGN) | 138 | if (parintr == SIG_IGN) | |
139 | return; | 139 | return; | |
140 | if (setintr && intty) | 140 | if (setintr && intty) | |
141 | stderror(ERR_NAME | ERR_TERMINAL); | 141 | stderror(ERR_NAME | ERR_TERMINAL); | |
142 | cp = gointr; | 142 | cp = gointr; | |
143 | gointr = 0; | 143 | gointr = 0; | |
144 | free(cp); | 144 | free(cp); | |
145 | if (vv == 0) { | 145 | if (vv == 0) { | |
146 | if (setintr) { | 146 | if (setintr) { | |
147 | sigemptyset(&nsigset); | 147 | sigemptyset(&nsigset); | |
148 | (void)sigaddset(&nsigset, SIGINT); | 148 | (void)sigaddset(&nsigset, SIGINT); | |
149 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); | 149 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); | |
150 | } else | 150 | } else | |
151 | (void)signal(SIGINT, SIG_DFL); | 151 | (void)signal(SIGINT, SIG_DFL); | |
152 | gointr = 0; | 152 | gointr = 0; | |
153 | } | 153 | } | |
154 | else if (eq((vv = strip(vv)), STRminus)) { | 154 | else if (eq((vv = strip(vv)), STRminus)) { | |
155 | (void)signal(SIGINT, SIG_IGN); | 155 | (void)signal(SIGINT, SIG_IGN); | |
156 | gointr = Strsave(STRminus); | 156 | gointr = Strsave(STRminus); | |
157 | } | 157 | } | |
158 | else { | 158 | else { | |
159 | gointr = Strsave(vv); | 159 | gointr = Strsave(vv); | |
160 | (void)signal(SIGINT, pintr); | 160 | (void)signal(SIGINT, pintr); | |
161 | } | 161 | } | |
162 | } | 162 | } | |
163 | 163 | |||
164 | void | 164 | void | |
165 | /*ARGSUSED*/ | 165 | /*ARGSUSED*/ | |
166 | donohup(Char **v, struct command *t) | 166 | donohup(Char **v, struct command *t) | |
167 | { | 167 | { | |
168 | if (intty) | 168 | if (intty) | |
169 | stderror(ERR_NAME | ERR_TERMINAL); | 169 | stderror(ERR_NAME | ERR_TERMINAL); | |
170 | if (setintr == 0) { | 170 | if (setintr == 0) { | |
171 | (void) signal(SIGHUP, SIG_IGN); | 171 | (void) signal(SIGHUP, SIG_IGN); | |
172 | } | 172 | } | |
173 | } | 173 | } | |
174 | 174 | |||
175 | void | 175 | void | |
176 | /*ARGSUSED*/ | 176 | /*ARGSUSED*/ | |
177 | dozip(Char **v, struct command *t) | 177 | dozip(Char **v, struct command *t) | |
178 | { | 178 | { | |
179 | ; | 179 | ; | |
180 | } | 180 | } | |
181 | 181 | |||
182 | void | 182 | void | |
183 | prvars(void) | 183 | prvars(void) | |
184 | { | 184 | { | |
185 | plist(&shvhed); | 185 | plist(&shvhed); | |
186 | } | 186 | } | |
187 | 187 | |||
188 | void | 188 | void | |
189 | /*ARGSUSED*/ | 189 | /*ARGSUSED*/ | |
190 | doalias(Char **v, struct command *t) | 190 | doalias(Char **v, struct command *t) | |
191 | { | 191 | { | |
192 | struct varent *vp; | 192 | struct varent *vp; | |
193 | Char *p; | 193 | Char *p; | |
194 | 194 | |||
195 | v++; | 195 | v++; | |
196 | p = *v++; | 196 | p = *v++; | |
197 | if (p == 0) | 197 | if (p == 0) | |
198 | plist(&aliases); | 198 | plist(&aliases); | |
199 | else if (*v == 0) { | 199 | else if (*v == 0) { | |
200 | vp = adrof1(strip(p), &aliases); | 200 | vp = adrof1(strip(p), &aliases); | |
201 | if (vp) { | 201 | if (vp) { | |
202 | blkpr(cshout, vp->vec); | 202 | blkpr(cshout, vp->vec); | |
203 | (void) fputc('\n', cshout); | 203 | (void) fputc('\n', cshout); | |
204 | } | 204 | } | |
205 | } | 205 | } | |
206 | else { | 206 | else { | |
207 | if (eq(p, STRalias) || eq(p, STRunalias)) { | 207 | if (eq(p, STRalias) || eq(p, STRunalias)) { | |
208 | setname(vis_str(p)); | 208 | setname(vis_str(p)); | |
209 | stderror(ERR_NAME | ERR_DANGER); | 209 | stderror(ERR_NAME | ERR_DANGER); | |
210 | } | 210 | } | |
211 | set1(strip(p), saveblk(v), &aliases); | 211 | set1(strip(p), saveblk(v), &aliases); | |
212 | } | 212 | } | |
213 | } | 213 | } | |
214 | 214 | |||
215 | void | 215 | void | |
216 | /*ARGSUSED*/ | 216 | /*ARGSUSED*/ | |
217 | unalias(Char **v, struct command *t) | 217 | unalias(Char **v, struct command *t) | |
218 | { | 218 | { | |
219 | unset1(v, &aliases); | 219 | unset1(v, &aliases); | |
220 | } | 220 | } | |
221 | 221 | |||
222 | void | 222 | void | |
223 | /*ARGSUSED*/ | 223 | /*ARGSUSED*/ | |
224 | dologout(Char **v, struct command *t) | 224 | dologout(Char **v, struct command *t) | |
225 | { | 225 | { | |
226 | islogin(); | 226 | islogin(); | |
227 | goodbye(); | 227 | goodbye(); | |
228 | } | 228 | } | |
229 | 229 | |||
230 | void | 230 | void | |
231 | /*ARGSUSED*/ | 231 | /*ARGSUSED*/ | |
232 | dologin(Char **v, struct command *t) | 232 | dologin(Char **v, struct command *t) | |
233 | { | 233 | { | |
234 | islogin(); | 234 | islogin(); | |
235 | rechist(); | 235 | rechist(); | |
236 | (void)signal(SIGTERM, parterm); | 236 | (void)signal(SIGTERM, parterm); | |
237 | (void)execl(_PATH_LOGIN, "login", short2str(v[1]), NULL); | 237 | (void)execl(_PATH_LOGIN, "login", short2str(v[1]), NULL); | |
238 | untty(); | 238 | untty(); | |
239 | xexit(1); | 239 | xexit(1); | |
240 | /* NOTREACHED */ | 240 | /* NOTREACHED */ | |
241 | } | 241 | } | |
242 | 242 | |||
243 | static void | 243 | static void | |
244 | islogin(void) | 244 | islogin(void) | |
245 | { | 245 | { | |
246 | if (chkstop == 0 && setintr) | 246 | if (chkstop == 0 && setintr) | |
247 | panystop(0); | 247 | panystop(0); | |
248 | if (loginsh) | 248 | if (loginsh) | |
249 | return; | 249 | return; | |
250 | stderror(ERR_NOTLOGIN); | 250 | stderror(ERR_NOTLOGIN); | |
251 | /* NOTREACHED */ | 251 | /* NOTREACHED */ | |
252 | } | 252 | } | |
253 | 253 | |||
254 | void | 254 | void | |
255 | doif(Char **v, struct command *kp) | 255 | doif(Char **v, struct command *kp) | |
256 | { | 256 | { | |
257 | Char **vv; | 257 | Char **vv; | |
258 | int i; | 258 | int i; | |
259 | 259 | |||
260 | v++; | 260 | v++; | |
261 | i = expr(&v); | 261 | i = expr(&v); | |
262 | vv = v; | 262 | vv = v; | |
263 | if (*vv == NULL) | 263 | if (*vv == NULL) | |
264 | stderror(ERR_NAME | ERR_EMPTYIF); | 264 | stderror(ERR_NAME | ERR_EMPTYIF); | |
265 | if (eq(*vv, STRthen)) { | 265 | if (eq(*vv, STRthen)) { | |
266 | if (*++vv) | 266 | if (*++vv) | |
267 | stderror(ERR_NAME | ERR_IMPRTHEN); | 267 | stderror(ERR_NAME | ERR_IMPRTHEN); | |
268 | setname(vis_str(STRthen)); | 268 | setname(vis_str(STRthen)); | |
269 | /* | 269 | /* | |
270 | * If expression was zero, then scan to else, otherwise just fall into | 270 | * If expression was zero, then scan to else, otherwise just fall into | |
271 | * following code. | 271 | * following code. | |
272 | */ | 272 | */ | |
273 | if (!i) | 273 | if (!i) | |
274 | search(T_IF, 0, NULL); | 274 | search(T_IF, 0, NULL); | |
275 | return; | 275 | return; | |
276 | } | 276 | } | |
277 | /* | 277 | /* | |
278 | * Simple command attached to this if. Left shift the node in this tree, | 278 | * Simple command attached to this if. Left shift the node in this tree, | |
279 | * munging it so we can reexecute it. | 279 | * munging it so we can reexecute it. | |
280 | */ | 280 | */ | |
281 | if (i) { | 281 | if (i) { | |
282 | lshift(kp->t_dcom, (size_t)(vv - kp->t_dcom)); | 282 | lshift(kp->t_dcom, (size_t)(vv - kp->t_dcom)); | |
283 | reexecute(kp); | 283 | reexecute(kp); | |
284 | donefds(); | 284 | donefds(); | |
285 | } | 285 | } | |
286 | } | 286 | } | |
287 | 287 | |||
288 | /* | 288 | /* | |
289 | * Reexecute a command, being careful not | 289 | * Reexecute a command, being careful not | |
290 | * to redo i/o redirection, which is already set up. | 290 | * to redo i/o redirection, which is already set up. | |
291 | */ | 291 | */ | |
292 | static void | 292 | static void | |
293 | reexecute(struct command *kp) | 293 | reexecute(struct command *kp) | |
294 | { | 294 | { | |
295 | kp->t_dflg &= F_SAVE; | 295 | kp->t_dflg &= F_SAVE; | |
296 | kp->t_dflg |= F_REPEAT; | 296 | kp->t_dflg |= F_REPEAT; | |
297 | /* | 297 | /* | |
298 | * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set | 298 | * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set | |
299 | * pgrp's as the jobs would then have no way to get the tty (we can't give | 299 | * pgrp's as the jobs would then have no way to get the tty (we can't give | |
300 | * it to them, and our parent wouldn't know their pgrp, etc. | 300 | * it to them, and our parent wouldn't know their pgrp, etc. | |
301 | */ | 301 | */ | |
302 | execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL); | 302 | execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL); | |
303 | } | 303 | } | |
304 | 304 | |||
305 | void | 305 | void | |
306 | /*ARGSUSED*/ | 306 | /*ARGSUSED*/ | |
307 | doelse(Char **v, struct command *t) | 307 | doelse(Char **v, struct command *t) | |
308 | { | 308 | { | |
309 | search(T_ELSE, 0, NULL); | 309 | search(T_ELSE, 0, NULL); | |
310 | } | 310 | } | |
311 | 311 | |||
312 | void | 312 | void | |
313 | /*ARGSUSED*/ | 313 | /*ARGSUSED*/ | |
314 | dogoto(Char **v, struct command *t) | 314 | dogoto(Char **v, struct command *t) | |
315 | { | 315 | { | |
316 | Char *lp; | 316 | Char *lp; | |
317 | 317 | |||
318 | gotolab(lp = globone(v[1], G_ERROR)); | 318 | gotolab(lp = globone(v[1], G_ERROR)); | |
319 | free(lp); | 319 | free(lp); | |
320 | } | 320 | } | |
321 | 321 | |||
322 | void | 322 | void | |
323 | gotolab(Char *lab) | 323 | gotolab(Char *lab) | |
324 | { | 324 | { | |
325 | struct whyle *wp; | 325 | struct whyle *wp; | |
326 | /* | 326 | /* | |
327 | * While we still can, locate any unknown ends of existing loops. This | 327 | * While we still can, locate any unknown ends of existing loops. This | |
328 | * obscure code is the WORST result of the fact that we don't really parse. | 328 | * obscure code is the WORST result of the fact that we don't really parse. | |
329 | */ | 329 | */ | |
330 | for (wp = whyles; wp; wp = wp->w_next) | 330 | for (wp = whyles; wp; wp = wp->w_next) | |
331 | if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) { | 331 | if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) { | |
332 | search(T_BREAK, 0, NULL); | 332 | search(T_BREAK, 0, NULL); | |
333 | btell(&wp->w_end); | 333 | btell(&wp->w_end); | |
334 | } | 334 | } | |
335 | else | 335 | else | |
336 | bseek(&wp->w_end); | 336 | bseek(&wp->w_end); | |
337 | search(T_GOTO, 0, lab); | 337 | search(T_GOTO, 0, lab); | |
338 | /* | 338 | /* | |
339 | * Eliminate loops which were exited. | 339 | * Eliminate loops which were exited. | |
340 | */ | 340 | */ | |
341 | wfree(); | 341 | wfree(); | |
342 | } | 342 | } | |
343 | 343 | |||
344 | void | 344 | void | |
345 | /*ARGSUSED*/ | 345 | /*ARGSUSED*/ | |
346 | doswitch(Char **v, struct command *t) | 346 | doswitch(Char **v, struct command *t) | |
347 | { | 347 | { | |
348 | Char *cp, *lp; | 348 | Char *cp, *lp; | |
349 | 349 | |||
350 | v++; | 350 | v++; | |
351 | if (!*v || *(*v++) != '(') | 351 | if (!*v || *(*v++) != '(') | |
352 | stderror(ERR_SYNTAX); | 352 | stderror(ERR_SYNTAX); | |
353 | cp = **v == ')' ? STRNULL : *v++; | 353 | cp = **v == ')' ? STRNULL : *v++; | |
354 | if (*(*v++) != ')') | 354 | if (*(*v++) != ')') | |
355 | v--; | 355 | v--; | |
356 | if (*v) | 356 | if (*v) | |
357 | stderror(ERR_SYNTAX); | 357 | stderror(ERR_SYNTAX); | |
358 | search(T_SWITCH, 0, lp = globone(cp, G_ERROR)); | 358 | search(T_SWITCH, 0, lp = globone(cp, G_ERROR)); | |
359 | free(lp); | 359 | free(lp); | |
360 | } | 360 | } | |
361 | 361 | |||
362 | void | 362 | void | |
363 | /*ARGSUSED*/ | 363 | /*ARGSUSED*/ | |
364 | dobreak(Char **v, struct command *t) | 364 | dobreak(Char **v, struct command *t) | |
365 | { | 365 | { | |
366 | if (whyles) | 366 | if (whyles) | |
367 | toend(); | 367 | toend(); | |
368 | else | 368 | else | |
369 | stderror(ERR_NAME | ERR_NOTWHILE); | 369 | stderror(ERR_NAME | ERR_NOTWHILE); | |
370 | } | 370 | } | |
371 | 371 | |||
372 | void | 372 | void | |
373 | /*ARGSUSED*/ | 373 | /*ARGSUSED*/ | |
374 | doexit(Char **v, struct command *t) | 374 | doexit(Char **v, struct command *t) | |
375 | { | 375 | { | |
376 | if (chkstop == 0 && (intty || intact) && evalvec == 0) | 376 | if (chkstop == 0 && (intty || intact) && evalvec == 0) | |
377 | panystop(0); | 377 | panystop(0); | |
378 | /* | 378 | /* | |
379 | * Don't DEMAND parentheses here either. | 379 | * Don't DEMAND parentheses here either. | |
380 | */ | 380 | */ | |
381 | v++; | 381 | v++; | |
382 | if (*v) { | 382 | if (*v) { | |
383 | set(STRstatus, putn(expr(&v))); | 383 | set(STRstatus, putn(expr(&v))); | |
384 | if (*v) | 384 | if (*v) | |
385 | stderror(ERR_NAME | ERR_EXPRESSION); | 385 | stderror(ERR_NAME | ERR_EXPRESSION); | |
386 | } | 386 | } | |
387 | btoeof(); | 387 | btoeof(); | |
388 | if (intty) | 388 | if (intty) | |
389 | (void) close(SHIN); | 389 | (void) close(SHIN); | |
390 | } | 390 | } | |
391 | 391 | |||
392 | void | 392 | void | |
393 | /*ARGSUSED*/ | 393 | /*ARGSUSED*/ | |
394 | doforeach(Char **v, struct command *t) | 394 | doforeach(Char **v, struct command *t) | |
395 | { | 395 | { | |
396 | struct whyle *nwp; | 396 | struct whyle *nwp; | |
397 | Char *cp, *sp; | 397 | Char *cp, *sp; | |
398 | 398 | |||
399 | v++; | 399 | v++; | |
400 | sp = cp = strip(*v); | 400 | sp = cp = strip(*v); | |
401 | if (!letter(*sp)) | 401 | if (!letter(*sp)) | |
402 | stderror(ERR_NAME | ERR_VARBEGIN); | 402 | stderror(ERR_NAME | ERR_VARBEGIN); | |
403 | while (*cp && alnum(*cp)) | 403 | while (*cp && alnum(*cp)) | |
404 | cp++; | 404 | cp++; | |
405 | if (*cp) | 405 | if (*cp) | |
406 | stderror(ERR_NAME | ERR_VARALNUM); | 406 | stderror(ERR_NAME | ERR_VARALNUM); | |
407 | if ((cp - sp) > MAXVARLEN) | 407 | if ((cp - sp) > MAXVARLEN) | |
408 | stderror(ERR_NAME | ERR_VARTOOLONG); | 408 | stderror(ERR_NAME | ERR_VARTOOLONG); | |
409 | cp = *v++; | 409 | cp = *v++; | |
410 | if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') | 410 | if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') | |
411 | stderror(ERR_NAME | ERR_NOPAREN); | 411 | stderror(ERR_NAME | ERR_NOPAREN); | |
412 | v++; | 412 | v++; | |
413 | gflag = 0, tglob(v); | 413 | gflag = 0, tglob(v); | |
414 | v = globall(v); | 414 | v = globall(v); | |
415 | if (v == 0) | 415 | if (v == 0) | |
416 | stderror(ERR_NAME | ERR_NOMATCH); | 416 | stderror(ERR_NAME | ERR_NOMATCH); | |
417 | nwp = xcalloc(1, sizeof *nwp); | 417 | nwp = xcalloc(1, sizeof *nwp); | |
418 | nwp->w_fe = nwp->w_fe0 = v; | 418 | nwp->w_fe = nwp->w_fe0 = v; | |
419 | gargv = 0; | 419 | gargv = 0; | |
420 | btell(&nwp->w_start); | 420 | btell(&nwp->w_start); | |
421 | nwp->w_fename = Strsave(cp); | 421 | nwp->w_fename = Strsave(cp); | |
422 | nwp->w_next = whyles; | 422 | nwp->w_next = whyles; | |
423 | nwp->w_end.type = F_SEEK; | 423 | nwp->w_end.type = F_SEEK; | |
424 | whyles = nwp; | 424 | whyles = nwp; | |
425 | /* | 425 | /* | |
426 | * Pre-read the loop so as to be more comprehensible to a terminal user. | 426 | * Pre-read the loop so as to be more comprehensible to a terminal user. | |
427 | */ | 427 | */ | |
428 | if (intty) | 428 | if (intty) | |
429 | preread(); | 429 | preread(); | |
430 | doagain(); | 430 | doagain(); | |
431 | } | 431 | } | |
432 | 432 | |||
433 | void | 433 | void | |
434 | /*ARGSUSED*/ | 434 | /*ARGSUSED*/ | |
435 | dowhile(Char **v, struct command *t) | 435 | dowhile(Char **v, struct command *t) | |
436 | { | 436 | { | |
437 | int status; | 437 | int status; | |
438 | int again; | 438 | int again; | |
439 | 439 | |||
440 | again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) && | 440 | again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) && | |
441 | whyles->w_fename == 0; | 441 | whyles->w_fename == 0; | |
442 | v++; | 442 | v++; | |
443 | /* | 443 | /* | |
444 | * Implement prereading here also, taking care not to evaluate the | 444 | * Implement prereading here also, taking care not to evaluate the | |
445 | * expression before the loop has been read up from a terminal. | 445 | * expression before the loop has been read up from a terminal. | |
446 | */ | 446 | */ | |
447 | if (intty && !again) | 447 | if (intty && !again) | |
448 | status = !exp0(&v, 1); | 448 | status = !exp0(&v, 1); | |
449 | else | 449 | else | |
450 | status = !expr(&v); | 450 | status = !expr(&v); | |
451 | if (*v) | 451 | if (*v) | |
452 | stderror(ERR_NAME | ERR_EXPRESSION); | 452 | stderror(ERR_NAME | ERR_EXPRESSION); | |
453 | if (!again) { | 453 | if (!again) { | |
454 | struct whyle *nwp = | 454 | struct whyle *nwp = | |
455 | xcalloc(1, sizeof(*nwp)); | 455 | xcalloc(1, sizeof(*nwp)); | |
456 | 456 | |||
457 | nwp->w_start = lineloc; | 457 | nwp->w_start = lineloc; | |
458 | nwp->w_end.type = F_SEEK; | 458 | nwp->w_end.type = F_SEEK; | |
459 | nwp->w_end.f_seek = 0; | 459 | nwp->w_end.f_seek = 0; | |
460 | nwp->w_next = whyles; | 460 | nwp->w_next = whyles; | |
461 | whyles = nwp; | 461 | whyles = nwp; | |
462 | if (intty) { | 462 | if (intty) { | |
463 | /* | 463 | /* | |
464 | * The tty preread | 464 | * The tty preread | |
465 | */ | 465 | */ | |
466 | preread(); | 466 | preread(); | |
467 | doagain(); | 467 | doagain(); | |
468 | return; | 468 | return; | |
469 | } | 469 | } | |
470 | } | 470 | } | |
471 | if (status) | 471 | if (status) | |
472 | /* We ain't gonna loop no more, no more! */ | 472 | /* We ain't gonna loop no more, no more! */ | |
473 | toend(); | 473 | toend(); | |
474 | } | 474 | } | |
475 | 475 | |||
476 | static void | 476 | static void | |
477 | preread(void) | 477 | preread(void) | |
478 | { | 478 | { | |
479 | sigset_t nsigset; | 479 | sigset_t nsigset; | |
480 | 480 | |||
481 | whyles->w_end.type = I_SEEK; | 481 | whyles->w_end.type = I_SEEK; | |
482 | if (setintr) { | 482 | if (setintr) { | |
483 | sigemptyset(&nsigset); | 483 | sigemptyset(&nsigset); | |
484 | (void) sigaddset(&nsigset, SIGINT); | 484 | (void) sigaddset(&nsigset, SIGINT); | |
485 | (void) sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | 485 | (void) sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | |
486 | } | 486 | } | |
487 | 487 | |||
488 | search(T_BREAK, 0, NULL); /* read the expression in */ | 488 | search(T_BREAK, 0, NULL); /* read the expression in */ | |
489 | if (setintr) | 489 | if (setintr) | |
490 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); | 490 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); | |
491 | btell(&whyles->w_end); | 491 | btell(&whyles->w_end); | |
492 | } | 492 | } | |
493 | 493 | |||
494 | void | 494 | void | |
495 | /*ARGSUSED*/ | 495 | /*ARGSUSED*/ | |
496 | doend(Char **v, struct command *t) | 496 | doend(Char **v, struct command *t) | |
497 | { | 497 | { | |
498 | if (!whyles) | 498 | if (!whyles) | |
499 | stderror(ERR_NAME | ERR_NOTWHILE); | 499 | stderror(ERR_NAME | ERR_NOTWHILE); | |
500 | btell(&whyles->w_end); | 500 | btell(&whyles->w_end); | |
501 | doagain(); | 501 | doagain(); | |
502 | } | 502 | } | |
503 | 503 | |||
504 | void | 504 | void | |
505 | /*ARGSUSED*/ | 505 | /*ARGSUSED*/ | |
506 | docontin(Char **v, struct command *t) | 506 | docontin(Char **v, struct command *t) | |
507 | { | 507 | { | |
508 | if (!whyles) | 508 | if (!whyles) | |
509 | stderror(ERR_NAME | ERR_NOTWHILE); | 509 | stderror(ERR_NAME | ERR_NOTWHILE); | |
510 | doagain(); | 510 | doagain(); | |
511 | } | 511 | } | |
512 | 512 | |||
513 | static void | 513 | static void | |
514 | doagain(void) | 514 | doagain(void) | |
515 | { | 515 | { | |
516 | /* Repeating a while is simple */ | 516 | /* Repeating a while is simple */ | |
517 | if (whyles->w_fename == 0) { | 517 | if (whyles->w_fename == 0) { | |
518 | bseek(&whyles->w_start); | 518 | bseek(&whyles->w_start); | |
519 | return; | 519 | return; | |
520 | } | 520 | } | |
521 | /* | 521 | /* | |
522 | * The foreach variable list actually has a spurious word ")" at the end of | 522 | * The foreach variable list actually has a spurious word ")" at the end of | |
523 | * the w_fe list. Thus we are at the of the list if one word beyond this | 523 | * the w_fe list. Thus we are at the of the list if one word beyond this | |
524 | * is 0. | 524 | * is 0. | |
525 | */ | 525 | */ | |
526 | if (!whyles->w_fe[1]) { | 526 | if (!whyles->w_fe[1]) { | |
527 | dobreak(NULL, NULL); | 527 | dobreak(NULL, NULL); | |
528 | return; | 528 | return; | |
529 | } | 529 | } | |
530 | set(whyles->w_fename, Strsave(*whyles->w_fe++)); | 530 | set(whyles->w_fename, Strsave(*whyles->w_fe++)); | |
531 | bseek(&whyles->w_start); | 531 | bseek(&whyles->w_start); | |
532 | } | 532 | } | |
533 | 533 | |||
534 | void | 534 | void | |
535 | dorepeat(Char **v, struct command *kp) | 535 | dorepeat(Char **v, struct command *kp) | |
536 | { | 536 | { | |
537 | int i; | 537 | int i; | |
538 | sigset_t nsigset; | 538 | sigset_t nsigset; | |
539 | 539 | |||
540 | i = getn(v[1]); | 540 | i = getn(v[1]); | |
541 | if (setintr) { | 541 | if (setintr) { | |
542 | sigemptyset(&nsigset); | 542 | sigemptyset(&nsigset); | |
543 | (void)sigaddset(&nsigset, SIGINT); | 543 | (void)sigaddset(&nsigset, SIGINT); | |
544 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); | 544 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); | |
545 | } | 545 | } | |
546 | lshift(v, 2); | 546 | lshift(v, 2); | |
547 | while (i > 0) { | 547 | while (i > 0) { | |
548 | if (setintr) | 548 | if (setintr) | |
549 | (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | 549 | (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | |
550 | reexecute(kp); | 550 | reexecute(kp); | |
551 | --i; | 551 | --i; | |
552 | } | 552 | } | |
553 | donefds(); | 553 | donefds(); | |
554 | if (setintr) | 554 | if (setintr) | |
555 | (void) sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | 555 | (void) sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | |
556 | } | 556 | } | |
557 | 557 | |||
558 | void | 558 | void | |
559 | /*ARGSUSED*/ | 559 | /*ARGSUSED*/ | |
560 | doswbrk(Char **v, struct command *t) | 560 | doswbrk(Char **v, struct command *t) | |
561 | { | 561 | { | |
562 | search(T_BRKSW, 0, NULL); | 562 | search(T_BRKSW, 0, NULL); | |
563 | } | 563 | } | |
564 | 564 | |||
565 | int | 565 | int | |
566 | srchx(Char *cp) | 566 | srchx(Char *cp) | |
567 | { | 567 | { | |
568 | struct srch *sp, *sp1, *sp2; | 568 | struct srch *sp, *sp1, *sp2; | |
569 | int i; | 569 | int i; | |
570 | 570 | |||
571 | /* | 571 | /* | |
572 | * Binary search Sp1 is the beginning of the current search range. Sp2 is | 572 | * Binary search Sp1 is the beginning of the current search range. Sp2 is | |
573 | * one past the end. | 573 | * one past the end. | |
574 | */ | 574 | */ | |
575 | for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { | 575 | for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { | |
576 | sp = sp1 + ((sp2 - sp1) >> 1); | 576 | sp = sp1 + ((sp2 - sp1) >> 1); | |
577 | if ((i = *cp - *sp->s_name) == 0 && | 577 | if ((i = *cp - *sp->s_name) == 0 && | |
578 | (i = Strcmp(cp, str2short(sp->s_name))) == 0) | 578 | (i = Strcmp(cp, str2short(sp->s_name))) == 0) | |
579 | return sp->s_value; | 579 | return sp->s_value; | |
580 | if (i < 0) | 580 | if (i < 0) | |
581 | sp2 = sp; | 581 | sp2 = sp; | |
582 | else | 582 | else | |
583 | sp1 = sp + 1; | 583 | sp1 = sp + 1; | |
584 | } | 584 | } | |
585 | return (-1); | 585 | return (-1); | |
586 | } | 586 | } | |
587 | 587 | |||
588 | static Char Stype; | 588 | static Char Stype; | |
589 | static Char *Sgoal; | 589 | static Char *Sgoal; | |
590 | 590 | |||
591 | /*VARARGS2*/ | 591 | /*VARARGS2*/ | |
592 | static void | 592 | static void | |
593 | search(int type, int level, Char *goal) | 593 | search(int type, int level, Char *goal) | |
594 | { | 594 | { | |
595 | Char wordbuf[BUFSIZE]; | 595 | Char wordbuf[BUFSIZE]; | |
596 | Char *aword, *cp; | 596 | Char *aword, *cp; | |
597 | struct whyle *wp; | 597 | struct whyle *wp; | |
598 | int wlevel = 0; | 598 | int wlevel = 0; | |
599 | 599 | |||
600 | aword = wordbuf; | 600 | aword = wordbuf; | |
601 | Stype = (Char)type; | 601 | Stype = (Char)type; | |
602 | Sgoal = goal; | 602 | Sgoal = goal; | |
603 | if (type == T_GOTO) { | 603 | if (type == T_GOTO) { | |
604 | struct Ain a; | 604 | struct Ain a; | |
605 | a.type = F_SEEK; | 605 | a.type = F_SEEK; | |
606 | a.f_seek = 0; | 606 | a.f_seek = 0; | |
607 | bseek(&a); | 607 | bseek(&a); | |
608 | } | 608 | } | |
609 | do { | 609 | do { | |
610 | if (intty && fseekp == feobp && aret == F_SEEK) | 610 | if (intty && fseekp == feobp && aret == F_SEEK) | |
611 | (void)fprintf(cshout, "? "), (void)fflush(cshout); | 611 | (void)fprintf(cshout, "? "), (void)fflush(cshout); | |
612 | aword[0] = 0; | 612 | aword[0] = 0; | |
613 | (void)getword(aword); | 613 | (void)getword(aword); | |
614 | switch (srchx(aword)) { | 614 | switch (srchx(aword)) { | |
615 | case T_CASE: | 615 | case T_CASE: | |
616 | if (type != T_SWITCH || level != 0) | 616 | if (type != T_SWITCH || level != 0) | |
617 | break; | 617 | break; | |
618 | (void) getword(aword); | 618 | (void) getword(aword); | |
619 | if (lastchr(aword) == ':') | 619 | if (lastchr(aword) == ':') | |
620 | aword[Strlen(aword) - 1] = 0; | 620 | aword[Strlen(aword) - 1] = 0; | |
621 | cp = strip(Dfix1(aword)); | 621 | cp = strip(Dfix1(aword)); | |
622 | if (Gmatch(goal, cp)) | 622 | if (Gmatch(goal, cp)) | |
623 | level = -1; | 623 | level = -1; | |
624 | free(cp); | 624 | free(cp); | |
625 | break; | 625 | break; | |
626 | case T_DEFAULT: | 626 | case T_DEFAULT: | |
627 | if (type == T_SWITCH && level == 0) | 627 | if (type == T_SWITCH && level == 0) | |
628 | level = -1; | 628 | level = -1; | |
629 | break; | 629 | break; | |
630 | case T_ELSE: | 630 | case T_ELSE: | |
631 | if (level == 0 && type == T_IF) | 631 | if (level == 0 && type == T_IF) | |
632 | return; | 632 | return; | |
633 | break; | 633 | break; | |
634 | case T_END: | 634 | case T_END: | |
635 | if (type == T_BRKSW) { | 635 | if (type == T_BRKSW) { | |
636 | if (wlevel == 0) { | 636 | if (wlevel == 0) { | |
637 | wp = whyles; | 637 | wp = whyles; | |
638 | if (wp) { | 638 | if (wp) { | |
639 | whyles = wp->w_next; | 639 | whyles = wp->w_next; | |
640 | wpfree(wp); | 640 | wpfree(wp); | |
641 | } | 641 | } | |
642 | } | 642 | } | |
643 | } | 643 | } | |
644 | if (type == T_BREAK) | 644 | if (type == T_BREAK) | |
645 | level--; | 645 | level--; | |
646 | wlevel--; | 646 | wlevel--; | |
647 | break; | 647 | break; | |
648 | case T_ENDIF: | 648 | case T_ENDIF: | |
649 | if (type == T_IF || type == T_ELSE) | 649 | if (type == T_IF || type == T_ELSE) | |
650 | level--; | 650 | level--; | |
651 | break; | 651 | break; | |
652 | case T_ENDSW: | 652 | case T_ENDSW: | |
653 | if (type == T_SWITCH || type == T_BRKSW) | 653 | if (type == T_SWITCH || type == T_BRKSW) | |
654 | level--; | 654 | level--; | |
655 | break; | 655 | break; | |
656 | case T_IF: | 656 | case T_IF: | |
657 | while (getword(aword)) | 657 | while (getword(aword)) | |
658 | continue; | 658 | continue; | |
659 | if ((type == T_IF || type == T_ELSE) && | 659 | if ((type == T_IF || type == T_ELSE) && | |
660 | eq(aword, STRthen)) | 660 | eq(aword, STRthen)) | |
661 | level++; | 661 | level++; | |
662 | break; | 662 | break; | |
663 | case T_LABEL: | 663 | case T_LABEL: | |
664 | if (type == T_GOTO && getword(aword) && eq(aword, goal)) | 664 | if (type == T_GOTO && getword(aword) && eq(aword, goal)) | |
665 | level = -1; | 665 | level = -1; | |
666 | break; | 666 | break; | |
667 | case T_SWITCH: | 667 | case T_SWITCH: | |
668 | if (type == T_SWITCH || type == T_BRKSW) | 668 | if (type == T_SWITCH || type == T_BRKSW) | |
669 | level++; | 669 | level++; | |
670 | break; | 670 | break; | |
671 | case T_FOREACH: | 671 | case T_FOREACH: | |
672 | case T_WHILE: | 672 | case T_WHILE: | |
673 | wlevel++; | 673 | wlevel++; | |
674 | if (type == T_BREAK) | 674 | if (type == T_BREAK) | |
675 | level++; | 675 | level++; | |
676 | break; | 676 | break; | |
677 | default: | 677 | default: | |
678 | if (type != T_GOTO && (type != T_SWITCH || level != 0)) | 678 | if (type != T_GOTO && (type != T_SWITCH || level != 0)) | |
679 | break; | 679 | break; | |
680 | if (lastchr(aword) != ':') | 680 | if (lastchr(aword) != ':') | |
681 | break; | 681 | break; | |
682 | aword[Strlen(aword) - 1] = 0; | 682 | aword[Strlen(aword) - 1] = 0; | |
683 | if ((type == T_GOTO && eq(aword, goal)) || | 683 | if ((type == T_GOTO && eq(aword, goal)) || | |
684 | (type == T_SWITCH && eq(aword, STRdefault))) | 684 | (type == T_SWITCH && eq(aword, STRdefault))) | |
685 | level = -1; | 685 | level = -1; | |
686 | break; | 686 | break; | |
687 | } | 687 | } | |
688 | (void) getword(NULL); | 688 | (void) getword(NULL); | |
689 | } while (level >= 0); | 689 | } while (level >= 0); | |
690 | } | 690 | } | |
691 | 691 | |||
692 | static void | 692 | static void | |
693 | wpfree(struct whyle *wp) | 693 | wpfree(struct whyle *wp) | |
694 | { | 694 | { | |
695 | if (wp->w_fe0) | 695 | if (wp->w_fe0) | |
696 | blkfree(wp->w_fe0); | 696 | blkfree(wp->w_fe0); | |
697 | if (wp->w_fename) | 697 | if (wp->w_fename) | |
698 | free(wp->w_fename); | 698 | free(wp->w_fename); | |
699 | free(wp); | 699 | free(wp); | |
700 | } | 700 | } | |
701 | 701 | |||
702 | static int | 702 | static int | |
703 | getword(Char *wp) | 703 | getword(Char *wp) | |
704 | { | 704 | { | |
705 | int c, d, found, kwd; | 705 | int c, d, found, kwd; | |
706 | Char *owp; | 706 | Char *owp; | |
707 | 707 | |||
708 | c = readc(1); | 708 | c = readc(1); | |
709 | d = 0; | 709 | d = 0; | |
710 | found = 0; | 710 | found = 0; | |
711 | kwd = 0; | 711 | kwd = 0; | |
712 | owp = wp; | 712 | owp = wp; | |
713 | do { | 713 | do { | |
714 | while (c == ' ' || c == '\t') | 714 | while (c == ' ' || c == '\t') | |
715 | c = readc(1); | 715 | c = readc(1); | |
716 | if (c == '#') | 716 | if (c == '#') | |
717 | do | 717 | do | |
718 | c = readc(1); | 718 | c = readc(1); | |
719 | while (c >= 0 && c != '\n'); | 719 | while (c >= 0 && c != '\n'); | |
720 | if (c < 0) | 720 | if (c < 0) | |
721 | goto past; | 721 | goto past; | |
722 | if (c == '\n') { | 722 | if (c == '\n') { | |
723 | if (wp) | 723 | if (wp) | |
724 | break; | 724 | break; | |
725 | return (0); | 725 | return (0); | |
726 | } | 726 | } | |
727 | unreadc(c); | 727 | unreadc(c); | |
728 | found = 1; | 728 | found = 1; | |
729 | do { | 729 | do { | |
730 | c = readc(1); | 730 | c = readc(1); | |
731 | if (c == '\\' && (c = readc(1)) == '\n') | 731 | if (c == '\\' && (c = readc(1)) == '\n') | |
732 | c = ' '; | 732 | c = ' '; | |
733 | if (c == '\'' || c == '"') { | 733 | if (c == '\'' || c == '"') { | |
734 | if (d == 0) | 734 | if (d == 0) | |
735 | d = c; | 735 | d = c; | |
736 | else if (d == c) | 736 | else if (d == c) | |
737 | d = 0; | 737 | d = 0; | |
738 | } | 738 | } | |
739 | if (c < 0) | 739 | if (c < 0) | |
740 | goto past; | 740 | goto past; | |
741 | if (wp) { | 741 | if (wp) { | |
742 | *wp++ = (Char)c; | 742 | *wp++ = (Char)c; | |
743 | *wp = 0; /* end the string b4 test */ | 743 | *wp = 0; /* end the string b4 test */ | |
744 | } | 744 | } | |
745 | } while ((d || (!(kwd = keyword(owp)) && c != ' ' | 745 | } while ((d || (!(kwd = keyword(owp)) && c != ' ' | |
746 | && c != '\t')) && c != '\n'); | 746 | && c != '\t')) && c != '\n'); | |
747 | } while (wp == 0); | 747 | } while (wp == 0); | |
748 | 748 | |||
749 | /* | 749 | /* | |
750 | * if we have read a keyword ( "if", "switch" or "while" ) then we do not | 750 | * if we have read a keyword ( "if", "switch" or "while" ) then we do not | |
751 | * need to unreadc the look-ahead char | 751 | * need to unreadc the look-ahead char | |
752 | */ | 752 | */ | |
753 | if (!kwd) { | 753 | if (!kwd) { | |
754 | unreadc(c); | 754 | unreadc(c); | |
755 | if (found) | 755 | if (found) | |
756 | *--wp = 0; | 756 | *--wp = 0; | |
757 | } | 757 | } | |
758 | 758 | |||
759 | return (found); | 759 | return (found); | |
760 | 760 | |||
761 | past: | 761 | past: | |
762 | switch (Stype) { | 762 | switch (Stype) { | |
763 | case T_BREAK: | 763 | case T_BREAK: | |
764 | stderror(ERR_NAME | ERR_NOTFOUND, "end"); | 764 | stderror(ERR_NAME | ERR_NOTFOUND, "end"); | |
765 | /* NOTREACHED */ | 765 | /* NOTREACHED */ | |
766 | case T_ELSE: | 766 | case T_ELSE: | |
767 | stderror(ERR_NAME | ERR_NOTFOUND, "endif"); | 767 | stderror(ERR_NAME | ERR_NOTFOUND, "endif"); | |
768 | /* NOTREACHED */ | 768 | /* NOTREACHED */ | |
769 | case T_GOTO: | 769 | case T_GOTO: | |
770 | setname(vis_str(Sgoal)); | 770 | setname(vis_str(Sgoal)); | |
771 | stderror(ERR_NAME | ERR_NOTFOUND, "label"); | 771 | stderror(ERR_NAME | ERR_NOTFOUND, "label"); | |
772 | /* NOTREACHED */ | 772 | /* NOTREACHED */ | |
773 | case T_IF: | 773 | case T_IF: | |
774 | stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); | 774 | stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); | |
775 | /* NOTREACHED */ | 775 | /* NOTREACHED */ | |
776 | case T_BRKSW: | 776 | case T_BRKSW: | |
777 | case T_SWITCH: | 777 | case T_SWITCH: | |
778 | stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); | 778 | stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); | |
779 | /* NOTREACHED */ | 779 | /* NOTREACHED */ | |
780 | } | 780 | } | |
781 | return (0); | 781 | return (0); | |
782 | } | 782 | } | |
783 | 783 | |||
784 | /* | 784 | /* | |
785 | * keyword(wp) determines if wp is one of the built-n functions if, | 785 | * keyword(wp) determines if wp is one of the built-n functions if, | |
786 | * switch or while. It seems that when an if statement looks like | 786 | * switch or while. It seems that when an if statement looks like | |
787 | * "if(" then getword above sucks in the '(' and so the search routine | 787 | * "if(" then getword above sucks in the '(' and so the search routine | |
788 | * never finds what it is scanning for. Rather than rewrite doword, I hack | 788 | * never finds what it is scanning for. Rather than rewrite doword, I hack | |
789 | * in a test to see if the string forms a keyword. Then doword stops | 789 | * in a test to see if the string forms a keyword. Then doword stops | |
790 | * and returns the word "if" -strike | 790 | * and returns the word "if" -strike | |
791 | */ | 791 | */ | |
792 | 792 | |||
793 | static int | 793 | static int | |
794 | keyword(Char *wp) | 794 | keyword(Char *wp) | |
795 | { | 795 | { | |
796 | static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'}; | 796 | static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'}; | |
797 | static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'}; | 797 | static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'}; | |
798 | static Char STRif[] = {'i', 'f', '\0'}; | 798 | static Char STRif[] = {'i', 'f', '\0'}; | |
799 | 799 | |||
800 | if (!wp) | 800 | if (!wp) | |
801 | return (0); | 801 | return (0); | |
802 | 802 | |||
803 | if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0) | 803 | if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0) | |
804 | || (Strcmp(wp, STRswitch) == 0)) | 804 | || (Strcmp(wp, STRswitch) == 0)) | |
805 | return (1); | 805 | return (1); | |
806 | 806 | |||
807 | return (0); | 807 | return (0); | |
808 | } | 808 | } | |
809 | 809 | |||
810 | static void | 810 | static void | |
811 | toend(void) | 811 | toend(void) | |
812 | { | 812 | { | |
813 | if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) { | 813 | if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) { | |
814 | search(T_BREAK, 0, NULL); | 814 | search(T_BREAK, 0, NULL); | |
815 | btell(&whyles->w_end); | 815 | btell(&whyles->w_end); | |
816 | whyles->w_end.f_seek--; | 816 | whyles->w_end.f_seek--; | |
817 | } | 817 | } | |
818 | else | 818 | else | |
819 | bseek(&whyles->w_end); | 819 | bseek(&whyles->w_end); | |
820 | wfree(); | 820 | wfree(); | |
821 | } | 821 | } | |
822 | 822 | |||
823 | void | 823 | void | |
824 | wfree(void) | 824 | wfree(void) | |
825 | { | 825 | { | |
826 | struct Ain o; | 826 | struct Ain o; | |
827 | struct whyle *nwp; | 827 | struct whyle *nwp; | |
828 | 828 | |||
829 | btell(&o); | 829 | btell(&o); | |
830 | 830 | |||
831 | for (; whyles; whyles = nwp) { | 831 | for (; whyles; whyles = nwp) { | |
832 | struct whyle *wp = whyles; | 832 | struct whyle *wp = whyles; | |
833 | nwp = wp->w_next; | 833 | nwp = wp->w_next; | |
834 | 834 | |||
835 | /* | 835 | /* | |
836 | * We free loops that have different seek types. | 836 | * We free loops that have different seek types. | |
837 | */ | 837 | */ | |
838 | if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type && | 838 | if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type && | |
839 | wp->w_start.type == o.type) { | 839 | wp->w_start.type == o.type) { | |
840 | if (wp->w_end.type == F_SEEK) { | 840 | if (wp->w_end.type == F_SEEK) { | |
841 | if (o.f_seek >= wp->w_start.f_seek && | 841 | if (o.f_seek >= wp->w_start.f_seek && | |
842 | (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) | 842 | (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek)) | |
843 | break; | 843 | break; | |
844 | } | 844 | } | |
845 | else { | 845 | else { | |
846 | if (o.a_seek >= wp->w_start.a_seek && | 846 | if (o.a_seek >= wp->w_start.a_seek && | |
847 | (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) | 847 | (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek)) | |
848 | break; | 848 | break; | |
849 | } | 849 | } | |
850 | } | 850 | } | |
851 | 851 | |||
852 | wpfree(wp); | 852 | wpfree(wp); | |
853 | } | 853 | } | |
854 | } | 854 | } | |
855 | 855 | |||
856 | void | 856 | void | |
857 | /*ARGSUSED*/ | 857 | /*ARGSUSED*/ | |
858 | doecho(Char **v, struct command *t) | 858 | doecho(Char **v, struct command *t) | |
859 | { | 859 | { | |
860 | xecho(' ', v); | 860 | xecho(' ', v); | |
861 | } | 861 | } | |
862 | 862 | |||
863 | void | 863 | void | |
864 | /*ARGSUSED*/ | 864 | /*ARGSUSED*/ | |
865 | doglob(Char **v, struct command *t) | 865 | doglob(Char **v, struct command *t) | |
866 | { | 866 | { | |
867 | xecho(0, v); | 867 | xecho(0, v); | |
868 | (void)fflush(cshout); | 868 | (void)fflush(cshout); | |
869 | } | 869 | } | |
870 | 870 | |||
871 | static void | 871 | static void | |
872 | xecho(int sep, Char **v) | 872 | xecho(int sep, Char **v) | |
873 | { | 873 | { | |
874 | Char *cp; | 874 | Char *cp; | |
875 | sigset_t nsigset; | 875 | sigset_t nsigset; | |
876 | int nonl; | 876 | int nonl; | |
877 | 877 | |||
878 | nonl = 0; | 878 | nonl = 0; | |
879 | if (setintr) { | 879 | if (setintr) { | |
880 | sigemptyset(&nsigset); | 880 | sigemptyset(&nsigset); | |
881 | (void)sigaddset(&nsigset, SIGINT); | 881 | (void)sigaddset(&nsigset, SIGINT); | |
882 | (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | 882 | (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | |
883 | } | 883 | } | |
884 | v++; | 884 | v++; | |
885 | if (*v == 0) | 885 | if (*v == 0) | |
886 | goto done; | 886 | goto done; | |
887 | gflag = 0, tglob(v); | 887 | gflag = 0, tglob(v); | |
888 | if (gflag) { | 888 | if (gflag) { | |
889 | v = globall(v); | 889 | v = globall(v); | |
890 | if (v == 0) | 890 | if (v == 0) | |
891 | stderror(ERR_NAME | ERR_NOMATCH); | 891 | stderror(ERR_NAME | ERR_NOMATCH); | |
892 | } | 892 | } | |
893 | else { | 893 | else { | |
894 | v = gargv = saveblk(v); | 894 | v = gargv = saveblk(v); | |
895 | trim(v); | 895 | trim(v); | |
896 | } | 896 | } | |
897 | if (sep == ' ' && *v && eq(*v, STRmn)) | 897 | if (sep == ' ' && *v && eq(*v, STRmn)) | |
898 | nonl++, v++; | 898 | nonl++, v++; | |
899 | while ((cp = *v++) != NULL) { | 899 | while ((cp = *v++) != NULL) { | |
900 | int c; | 900 | int c; | |
901 | 901 | |||
902 | while ((c = *cp++) != '\0') | 902 | while ((c = *cp++) != '\0') | |
903 | (void)vis_fputc(c | QUOTE, cshout); | 903 | (void)vis_fputc(c | QUOTE, cshout); | |
904 | 904 | |||
905 | if (*v) | 905 | if (*v) | |
906 | (void)vis_fputc(sep | QUOTE, cshout); | 906 | (void)vis_fputc(sep | QUOTE, cshout); | |
907 | } | 907 | } | |
908 | done: | 908 | done: | |
909 | if (sep && nonl == 0) | 909 | if (sep && nonl == 0) | |
910 | (void)fputc('\n', cshout); | 910 | (void)fputc('\n', cshout); | |
911 | else | 911 | else | |
912 | (void)fflush(cshout); | 912 | (void)fflush(cshout); | |
913 | if (setintr) | 913 | if (setintr) | |
914 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); | 914 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); | |
915 | if (gargv) | 915 | if (gargv) | |
916 | blkfree(gargv), gargv = 0; | 916 | blkfree(gargv), gargv = 0; | |
917 | } | 917 | } | |
918 | 918 | |||
919 | void | 919 | void | |
920 | /*ARGSUSED*/ | 920 | /*ARGSUSED*/ | |
921 | dosetenv(Char **v, struct command *t) | 921 | dosetenv(Char **v, struct command *t) | |
922 | { | 922 | { | |
923 | Char *lp, *vp; | 923 | Char *lp, *vp; | |
924 | sigset_t nsigset; | 924 | sigset_t nsigset; | |
925 | 925 | |||
926 | v++; | 926 | v++; | |
927 | if ((vp = *v++) == 0) { | 927 | if ((vp = *v++) == 0) { | |
928 | Char **ep; | 928 | Char **ep; | |
929 | 929 | |||
930 | if (setintr) { | 930 | if (setintr) { | |
931 | sigemptyset(&nsigset); | 931 | sigemptyset(&nsigset); | |
932 | (void)sigaddset(&nsigset, SIGINT); | 932 | (void)sigaddset(&nsigset, SIGINT); | |
933 | (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | 933 | (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL); | |
934 | } | 934 | } | |
935 | for (ep = STR_environ; *ep; ep++) | 935 | for (ep = STR_environ; *ep; ep++) | |
936 | (void)fprintf(cshout, "%s\n", vis_str(*ep)); | 936 | (void)fprintf(cshout, "%s\n", vis_str(*ep)); | |
937 | return; | 937 | return; | |
938 | } | 938 | } | |
939 | if ((lp = *v++) == 0) | 939 | if ((lp = *v++) == 0) | |
940 | lp = STRNULL; | 940 | lp = STRNULL; | |
941 | Setenv(vp, lp = globone(lp, G_APPEND)); | 941 | Setenv(vp, lp = globone(lp, G_APPEND)); | |
942 | if (eq(vp, STRPATH)) { | 942 | if (eq(vp, STRPATH)) { | |
943 | importpath(lp); | 943 | importpath(lp); | |
944 | dohash(NULL, NULL); | 944 | dohash(NULL, NULL); | |
945 | } | 945 | } | |
946 | else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) { | 946 | else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) { | |
947 | #ifdef NLS | 947 | #ifdef NLS | |
948 | int k; | 948 | int k; | |
949 | 949 | |||
950 | (void)setlocale(LC_ALL, ""); | 950 | (void)setlocale(LC_ALL, ""); | |
951 | for (k = 0200; k <= 0377 && !Isprint(k); k++) | 951 | for (k = 0200; k <= 0377 && !Isprint(k); k++) | |
952 | continue; | 952 | continue; | |
953 | AsciiOnly = k > 0377; | 953 | AsciiOnly = k > 0377; | |
954 | #else | 954 | #else | |
955 | AsciiOnly = 0; | 955 | AsciiOnly = 0; | |
956 | #endif /* NLS */ | 956 | #endif /* NLS */ | |
957 | } | 957 | } | |
958 | free(lp); | 958 | free(lp); | |
959 | } | 959 | } | |
960 | 960 | |||
961 | void | 961 | void | |
962 | /*ARGSUSED*/ | 962 | /*ARGSUSED*/ | |
963 | dounsetenv(Char **v, struct command *t) | 963 | dounsetenv(Char **v, struct command *t) | |
964 | { | 964 | { | |
965 | static Char *name = NULL; | 965 | static Char *name = NULL; | |
966 | Char **ep, *p, *n; | 966 | Char **ep, *p, *n; | |
967 | int i, maxi; | 967 | int i, maxi; | |
968 | 968 | |||
969 | if (name) | 969 | if (name) | |
970 | free(name); | 970 | free(name); | |
971 | /* | 971 | /* | |
972 | * Find the longest environment variable | 972 | * Find the longest environment variable | |
973 | */ | 973 | */ | |
974 | for (maxi = 0, ep = STR_environ; *ep; ep++) { | 974 | for (maxi = 0, ep = STR_environ; *ep; ep++) { | |
975 | for (i = 0, p = *ep; *p && *p != '='; p++, i++) | 975 | for (i = 0, p = *ep; *p && *p != '='; p++, i++) | |
976 | continue; | 976 | continue; | |
977 | if (i > maxi) | 977 | if (i > maxi) | |
978 | maxi = i; | 978 | maxi = i; | |
979 | } | 979 | } | |
980 | 980 | |||
981 | name = xmalloc((size_t)(maxi + 1) * sizeof(Char)); | 981 | name = xreallocarray(NULL, (size_t)(maxi + 1), sizeof(Char)); | |
982 | 982 | |||
983 | while (++v && *v) | 983 | while (++v && *v) | |
984 | for (maxi = 1; maxi;) | 984 | for (maxi = 1; maxi;) | |
985 | for (maxi = 0, ep = STR_environ; *ep; ep++) { | 985 | for (maxi = 0, ep = STR_environ; *ep; ep++) { | |
986 | for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) | 986 | for (n = name, p = *ep; *p && *p != '='; *n++ = *p++) | |
987 | continue; | 987 | continue; | |
988 | *n = '\0'; | 988 | *n = '\0'; | |
989 | if (!Gmatch(name, *v)) | 989 | if (!Gmatch(name, *v)) | |
990 | continue; | 990 | continue; | |
991 | maxi = 1; | 991 | maxi = 1; | |
992 | if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) { | 992 | if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) { | |
993 | #ifdef NLS | 993 | #ifdef NLS | |
994 | int k; | 994 | int k; | |
995 | 995 | |||
996 | (void) setlocale(LC_ALL, ""); | 996 | (void) setlocale(LC_ALL, ""); | |
997 | for (k = 0200; k <= 0377 && !Isprint(k); k++) | 997 | for (k = 0200; k <= 0377 && !Isprint(k); k++) | |
998 | continue; | 998 | continue; | |
999 | AsciiOnly = k > 0377; | 999 | AsciiOnly = k > 0377; | |
1000 | #else | 1000 | #else | |
1001 | AsciiOnly = getenv("LANG") == NULL && | 1001 | AsciiOnly = getenv("LANG") == NULL && | |
1002 | getenv("LC_CTYPE") == NULL; | 1002 | getenv("LC_CTYPE") == NULL; | |
1003 | #endif /* NLS */ | 1003 | #endif /* NLS */ | |
1004 | } | 1004 | } | |
1005 | /* | 1005 | /* | |
1006 | * Delete name, and start again cause the environment changes | 1006 | * Delete name, and start again cause the environment changes | |
1007 | */ | 1007 | */ | |
1008 | Unsetenv(name); | 1008 | Unsetenv(name); | |
1009 | break; | 1009 | break; | |
1010 | } | 1010 | } | |
1011 | free(name); | 1011 | free(name); | |
1012 | name = NULL; | 1012 | name = NULL; | |
1013 | } | 1013 | } | |
1014 | 1014 | |||
1015 | void | 1015 | void | |
1016 | Setenv(Char *name, Char *val) | 1016 | Setenv(Char *name, Char *val) | |
1017 | { | 1017 | { | |
1018 | Char *blk[2], *cp, *dp, **ep, **oep; | 1018 | Char *blk[2], *cp, *dp, **ep, **oep; | |
1019 | 1019 | |||
1020 | ep = STR_environ; | 1020 | ep = STR_environ; | |
1021 | oep = ep; | 1021 | oep = ep; | |
1022 | 1022 | |||
1023 | for (; *ep; ep++) { | 1023 | for (; *ep; ep++) { | |
1024 | for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) | 1024 | for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) | |
1025 | continue; | 1025 | continue; | |
1026 | if (*cp != 0 || *dp != '=') | 1026 | if (*cp != 0 || *dp != '=') | |
1027 | continue; | 1027 | continue; | |
1028 | cp = Strspl(STRequal, val); | 1028 | cp = Strspl(STRequal, val); | |
1029 | free(* ep); | 1029 | free(* ep); | |
1030 | *ep = strip(Strspl(name, cp)); | 1030 | *ep = strip(Strspl(name, cp)); | |
1031 | free(cp); | 1031 | free(cp); | |
1032 | blkfree((Char **)environ); | 1032 | blkfree((Char **)environ); | |
1033 | environ = short2blk(STR_environ); | 1033 | environ = short2blk(STR_environ); | |
1034 | return; | 1034 | return; | |
1035 | } | 1035 | } | |
1036 | cp = Strspl(name, STRequal); | 1036 | cp = Strspl(name, STRequal); | |
1037 | blk[0] = strip(Strspl(cp, val)); | 1037 | blk[0] = strip(Strspl(cp, val)); | |
1038 | free(cp); | 1038 | free(cp); | |
1039 | blk[1] = 0; | 1039 | blk[1] = 0; | |
1040 | STR_environ = blkspl(STR_environ, blk); | 1040 | STR_environ = blkspl(STR_environ, blk); | |
1041 | blkfree((Char **)environ); | 1041 | blkfree((Char **)environ); | |
1042 | environ = short2blk(STR_environ); | 1042 | environ = short2blk(STR_environ); | |
1043 | free(oep); | 1043 | free(oep); | |
1044 | } | 1044 | } | |
1045 | 1045 | |||
1046 | static void | 1046 | static void | |
1047 | Unsetenv(Char *name) | 1047 | Unsetenv(Char *name) | |
1048 | { | 1048 | { | |
1049 | Char *cp, *dp, **ep, **oep; | 1049 | Char *cp, *dp, **ep, **oep; | |
1050 | 1050 | |||
1051 | ep = STR_environ; | 1051 | ep = STR_environ; | |
1052 | oep = ep; | 1052 | oep = ep; | |
1053 | 1053 | |||
1054 | for (; *ep; ep++) { | 1054 | for (; *ep; ep++) { | |
1055 | for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) | 1055 | for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) | |
1056 | continue; | 1056 | continue; | |
1057 | if (*cp != 0 || *dp != '=') | 1057 | if (*cp != 0 || *dp != '=') | |
1058 | continue; | 1058 | continue; | |
1059 | cp = *ep; | 1059 | cp = *ep; | |
1060 | *ep = 0; | 1060 | *ep = 0; | |
1061 | STR_environ = blkspl(STR_environ, ep + 1); | 1061 | STR_environ = blkspl(STR_environ, ep + 1); | |
1062 | environ = short2blk(STR_environ); | 1062 | environ = short2blk(STR_environ); | |
1063 | *ep = cp; | 1063 | *ep = cp; | |
1064 | free(cp); | 1064 | free(cp); | |
1065 | free(oep); | 1065 | free(oep); | |
1066 | return; | 1066 | return; | |
1067 | } | 1067 | } | |
1068 | } | 1068 | } | |
1069 | 1069 | |||
1070 | void | 1070 | void | |
1071 | /*ARGSUSED*/ | 1071 | /*ARGSUSED*/ | |
1072 | doumask(Char **v, struct command *t) | 1072 | doumask(Char **v, struct command *t) | |
1073 | { | 1073 | { | |
1074 | Char *cp; | 1074 | Char *cp; | |
1075 | mode_t i; | 1075 | mode_t i; | |
1076 | 1076 | |||
1077 | cp = v[1]; | 1077 | cp = v[1]; | |
1078 | if (cp == 0) { | 1078 | if (cp == 0) { | |
1079 | i = umask(0); | 1079 | i = umask(0); | |
1080 | (void)umask(i); | 1080 | (void)umask(i); | |
1081 | (void)fprintf(cshout, "%o\n", i); | 1081 | (void)fprintf(cshout, "%o\n", i); | |
1082 | return; | 1082 | return; | |
1083 | } | 1083 | } | |
1084 | i = 0; | 1084 | i = 0; | |
1085 | while (Isdigit(*cp) && *cp != '8' && *cp != '9') | 1085 | while (Isdigit(*cp) && *cp != '8' && *cp != '9') | |
1086 | i = i * 8 + (mode_t)(*cp++ - '0'); | 1086 | i = i * 8 + (mode_t)(*cp++ - '0'); | |
1087 | if (*cp || i > 0777) | 1087 | if (*cp || i > 0777) | |
1088 | stderror(ERR_NAME | ERR_MASK); | 1088 | stderror(ERR_NAME | ERR_MASK); | |
1089 | (void)umask(i); | 1089 | (void)umask(i); | |
1090 | } | 1090 | } | |
1091 | 1091 | |||
1092 | typedef rlim_t RLIM_TYPE; | 1092 | typedef rlim_t RLIM_TYPE; | |
1093 | 1093 | |||
1094 | static const struct limits { | 1094 | static const struct limits { | |
1095 | int limconst; | 1095 | int limconst; | |
1096 | const char *limname; | 1096 | const char *limname; | |
1097 | int limdiv; | 1097 | int limdiv; | |
1098 | const char *limscale; | 1098 | const char *limscale; | |
1099 | } limits[] = { | 1099 | } limits[] = { | |
1100 | { RLIMIT_CPU, "cputime", 1, "seconds" }, | 1100 | { RLIMIT_CPU, "cputime", 1, "seconds" }, | |
1101 | { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, | 1101 | { RLIMIT_FSIZE, "filesize", 1024, "kbytes" }, | |
1102 | { RLIMIT_DATA, "datasize", 1024, "kbytes" }, | 1102 | { RLIMIT_DATA, "datasize", 1024, "kbytes" }, | |
1103 | { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, | 1103 | { RLIMIT_STACK, "stacksize", 1024, "kbytes" }, | |
1104 | { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, | 1104 | { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" }, | |
1105 | { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, | 1105 | { RLIMIT_RSS, "memoryuse", 1024, "kbytes" }, | |
1106 | { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, | 1106 | { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" }, | |
1107 | { RLIMIT_NPROC, "maxproc", 1, "" }, | 1107 | { RLIMIT_NPROC, "maxproc", 1, "" }, | |
1108 | { RLIMIT_NTHR, "maxthread", 1, "" }, | 1108 | { RLIMIT_NTHR, "maxthread", 1, "" }, | |
1109 | { RLIMIT_NOFILE, "openfiles", 1, "" }, | 1109 | { RLIMIT_NOFILE, "openfiles", 1, "" }, | |
1110 | { RLIMIT_SBSIZE, "sbsize", 1, "bytes" }, | 1110 | { RLIMIT_SBSIZE, "sbsize", 1, "bytes" }, | |
1111 | { RLIMIT_AS, "vmemoryuse", 1024, "kbytes" }, | 1111 | { RLIMIT_AS, "vmemoryuse", 1024, "kbytes" }, | |
1112 | { -1, NULL, 0, NULL } | 1112 | { -1, NULL, 0, NULL } | |
1113 | }; | 1113 | }; | |
1114 | 1114 | |||
1115 | static const struct limits *findlim(Char *); | 1115 | static const struct limits *findlim(Char *); | |
1116 | static RLIM_TYPE getval(const struct limits *, Char **); | 1116 | static RLIM_TYPE getval(const struct limits *, Char **); | |
1117 | static void limtail(Char *, const char *); | 1117 | static void limtail(Char *, const char *); | |
1118 | static void plim(const struct limits *, Char); | 1118 | static void plim(const struct limits *, Char); | |
1119 | static int setlim(const struct limits *, Char, RLIM_TYPE); | 1119 | static int setlim(const struct limits *, Char, RLIM_TYPE); | |
1120 | 1120 | |||
1121 | static const struct limits * | 1121 | static const struct limits * | |
1122 | findlim(Char *cp) | 1122 | findlim(Char *cp) | |
1123 | { | 1123 | { | |
1124 | const struct limits *lp, *res; | 1124 | const struct limits *lp, *res; | |
1125 | 1125 | |||
1126 | res = NULL; | 1126 | res = NULL; | |
1127 | for (lp = limits; lp->limconst >= 0; lp++) | 1127 | for (lp = limits; lp->limconst >= 0; lp++) | |
1128 | if (prefix(cp, str2short(lp->limname))) { | 1128 | if (prefix(cp, str2short(lp->limname))) { | |
1129 | if (res) | 1129 | if (res) | |
1130 | stderror(ERR_NAME | ERR_AMBIG); | 1130 | stderror(ERR_NAME | ERR_AMBIG); | |
1131 | res = lp; | 1131 | res = lp; | |
1132 | } | 1132 | } | |
1133 | if (res) | 1133 | if (res) | |
1134 | return (res); | 1134 | return (res); | |
1135 | stderror(ERR_NAME | ERR_LIMIT); | 1135 | stderror(ERR_NAME | ERR_LIMIT); | |
1136 | /* NOTREACHED */ | 1136 | /* NOTREACHED */ | |
1137 | } | 1137 | } | |
1138 | 1138 | |||
1139 | void | 1139 | void | |
1140 | /*ARGSUSED*/ | 1140 | /*ARGSUSED*/ | |
1141 | dolimit(Char **v, struct command *t) | 1141 | dolimit(Char **v, struct command *t) | |
1142 | { | 1142 | { | |
1143 | const struct limits *lp; | 1143 | const struct limits *lp; | |
1144 | RLIM_TYPE limit; | 1144 | RLIM_TYPE limit; | |
1145 | char hard; | 1145 | char hard; | |
1146 | 1146 | |||
1147 | hard = 0; | 1147 | hard = 0; | |
1148 | v++; | 1148 | v++; | |
1149 | if (*v && eq(*v, STRmh)) { | 1149 | if (*v && eq(*v, STRmh)) { | |
1150 | hard = 1; | 1150 | hard = 1; | |
1151 | v++; | 1151 | v++; | |
1152 | } | 1152 | } | |
1153 | if (*v == 0) { | 1153 | if (*v == 0) { | |
1154 | for (lp = limits; lp->limconst >= 0; lp++) | 1154 | for (lp = limits; lp->limconst >= 0; lp++) | |
1155 | plim(lp, hard); | 1155 | plim(lp, hard); | |
1156 | return; | 1156 | return; | |
1157 | } | 1157 | } | |
1158 | lp = findlim(v[0]); | 1158 | lp = findlim(v[0]); | |
1159 | if (v[1] == 0) { | 1159 | if (v[1] == 0) { | |
1160 | plim(lp, hard); | 1160 | plim(lp, hard); | |
1161 | return; | 1161 | return; | |
1162 | } | 1162 | } | |
1163 | limit = getval(lp, v + 1); | 1163 | limit = getval(lp, v + 1); | |
1164 | if (setlim(lp, hard, limit) < 0) | 1164 | if (setlim(lp, hard, limit) < 0) | |
1165 | stderror(ERR_SILENT); | 1165 | stderror(ERR_SILENT); | |
1166 | } | 1166 | } | |
1167 | 1167 | |||
1168 | static RLIM_TYPE | 1168 | static RLIM_TYPE | |
1169 | getval(const struct limits *lp, Char **v) | 1169 | getval(const struct limits *lp, Char **v) | |
1170 | { | 1170 | { | |
1171 | Char *cp; | 1171 | Char *cp; | |
1172 | double d; | 1172 | double d; | |
1173 | 1173 | |||
1174 | cp = *v++; | 1174 | cp = *v++; | |
1175 | d = atof(short2str(cp)); | 1175 | d = atof(short2str(cp)); | |
1176 | 1176 | |||
1177 | while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') | 1177 | while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') | |
1178 | cp++; | 1178 | cp++; | |
1179 | if (*cp == 0) { | 1179 | if (*cp == 0) { | |
1180 | if (*v == 0) | 1180 | if (*v == 0) | |
1181 | return ((RLIM_TYPE)((d + 0.5) * lp->limdiv)); | 1181 | return ((RLIM_TYPE)((d + 0.5) * lp->limdiv)); | |
1182 | cp = *v; | 1182 | cp = *v; | |
1183 | } | 1183 | } | |
1184 | switch (*cp) { | 1184 | switch (*cp) { | |
1185 | case ':': | 1185 | case ':': | |
1186 | if (lp->limconst != RLIMIT_CPU) | 1186 | if (lp->limconst != RLIMIT_CPU) | |
1187 | goto badscal; | 1187 | goto badscal; | |
1188 | return ((RLIM_TYPE)(d * 60.0 + atof(short2str(cp + 1)))); | 1188 | return ((RLIM_TYPE)(d * 60.0 + atof(short2str(cp + 1)))); | |
1189 | case 'M': | 1189 | case 'M': | |
1190 | if (lp->limconst == RLIMIT_CPU) | 1190 | if (lp->limconst == RLIMIT_CPU) | |
1191 | goto badscal; | 1191 | goto badscal; | |
1192 | *cp = 'm'; | 1192 | *cp = 'm'; | |
1193 | limtail(cp, "megabytes"); | 1193 | limtail(cp, "megabytes"); | |
1194 | d *= 1024.0 * 1024.0; | 1194 | d *= 1024.0 * 1024.0; | |
1195 | break; | 1195 | break; | |
1196 | case 'h': | 1196 | case 'h': | |
1197 | if (lp->limconst != RLIMIT_CPU) | 1197 | if (lp->limconst != RLIMIT_CPU) | |
1198 | goto badscal; | 1198 | goto badscal; | |
1199 | limtail(cp, "hours"); | 1199 | limtail(cp, "hours"); | |
1200 | d *= 3600.0; | 1200 | d *= 3600.0; | |
1201 | break; | 1201 | break; | |
1202 | case 'k': | 1202 | case 'k': | |
1203 | if (lp->limconst == RLIMIT_CPU) | 1203 | if (lp->limconst == RLIMIT_CPU) | |
1204 | goto badscal; | 1204 | goto badscal; | |
1205 | limtail(cp, "kbytes"); | 1205 | limtail(cp, "kbytes"); | |
1206 | d *= 1024.0; | 1206 | d *= 1024.0; | |
1207 | break; | 1207 | break; | |
1208 | case 'm': | 1208 | case 'm': | |
1209 | if (lp->limconst == RLIMIT_CPU) { | 1209 | if (lp->limconst == RLIMIT_CPU) { | |
1210 | limtail(cp, "minutes"); | 1210 | limtail(cp, "minutes"); | |
1211 | d *= 60.0; | 1211 | d *= 60.0; | |
1212 | break; | 1212 | break; | |
1213 | } | 1213 | } | |
1214 | *cp = 'm'; | 1214 | *cp = 'm'; | |
1215 | limtail(cp, "megabytes"); | 1215 | limtail(cp, "megabytes"); | |
1216 | d *= 1024.0 * 1024.0; | 1216 | d *= 1024.0 * 1024.0; | |
1217 | break; | 1217 | break; | |
1218 | case 's': | 1218 | case 's': | |
1219 | if (lp->limconst != RLIMIT_CPU) | 1219 | if (lp->limconst != RLIMIT_CPU) | |
1220 | goto badscal; | 1220 | goto badscal; | |
1221 | limtail(cp, "seconds"); | 1221 | limtail(cp, "seconds"); | |
1222 | break; | 1222 | break; | |
1223 | case 'u': | 1223 | case 'u': | |
1224 | limtail(cp, "unlimited"); | 1224 | limtail(cp, "unlimited"); | |
1225 | return (RLIM_INFINITY); | 1225 | return (RLIM_INFINITY); | |
1226 | default: | 1226 | default: | |
1227 | badscal: | 1227 | badscal: | |
1228 | stderror(ERR_NAME | ERR_SCALEF); | 1228 | stderror(ERR_NAME | ERR_SCALEF); | |
1229 | /* NOTREACHED */ | 1229 | /* NOTREACHED */ | |
1230 | } | 1230 | } | |
1231 | d += 0.5; | 1231 | d += 0.5; | |
1232 | if (d > (double) RLIM_INFINITY) | 1232 | if (d > (double) RLIM_INFINITY) | |
1233 | return RLIM_INFINITY; | 1233 | return RLIM_INFINITY; | |
1234 | else | 1234 | else | |
1235 | return ((RLIM_TYPE)d); | 1235 | return ((RLIM_TYPE)d); | |
1236 | } | 1236 | } | |
1237 | 1237 | |||
1238 | static void | 1238 | static void | |
1239 | limtail(Char *cp, const char *str) | 1239 | limtail(Char *cp, const char *str) | |
1240 | { | 1240 | { | |
1241 | while (*cp && *cp == *str) | 1241 | while (*cp && *cp == *str) | |
1242 | cp++, str++; | 1242 | cp++, str++; | |
1243 | if (*cp) | 1243 | if (*cp) | |
1244 | stderror(ERR_BADSCALE, str); | 1244 | stderror(ERR_BADSCALE, str); | |
1245 | } | 1245 | } | |
1246 | 1246 | |||
1247 | 1247 | |||
1248 | /*ARGSUSED*/ | 1248 | /*ARGSUSED*/ | |
1249 | static void | 1249 | static void | |
1250 | plim(const struct limits *lp, Char hard) | 1250 | plim(const struct limits *lp, Char hard) | |
1251 | { | 1251 | { | |
1252 | struct rlimit rlim; | 1252 | struct rlimit rlim; | |
1253 | RLIM_TYPE limit; | 1253 | RLIM_TYPE limit; | |
1254 | 1254 | |||
1255 | (void)fprintf(cshout, "%-13.13s", lp->limname); | 1255 | (void)fprintf(cshout, "%-13.13s", lp->limname); | |
1256 | 1256 | |||
1257 | (void)getrlimit(lp->limconst, &rlim); | 1257 | (void)getrlimit(lp->limconst, &rlim); | |
1258 | limit = hard ? rlim.rlim_max : rlim.rlim_cur; | 1258 | limit = hard ? rlim.rlim_max : rlim.rlim_cur; | |
1259 | 1259 | |||
1260 | if (limit == RLIM_INFINITY) | 1260 | if (limit == RLIM_INFINITY) | |
1261 | (void)fprintf(cshout, "unlimited"); | 1261 | (void)fprintf(cshout, "unlimited"); | |
1262 | else if (lp->limconst == RLIMIT_CPU) | 1262 | else if (lp->limconst == RLIMIT_CPU) | |
1263 | psecs((long) limit); | 1263 | psecs((long) limit); | |
1264 | else | 1264 | else | |
1265 | (void)fprintf(cshout, "%jd %s", | 1265 | (void)fprintf(cshout, "%jd %s", | |
1266 | (intmax_t) (limit / (RLIM_TYPE)lp->limdiv), lp->limscale); | 1266 | (intmax_t) (limit / (RLIM_TYPE)lp->limdiv), lp->limscale); | |
1267 | (void)fputc('\n', cshout); | 1267 | (void)fputc('\n', cshout); | |
1268 | } | 1268 | } | |
1269 | 1269 | |||
1270 | void | 1270 | void | |
1271 | /*ARGSUSED*/ | 1271 | /*ARGSUSED*/ | |
1272 | dounlimit(Char **v, struct command *t) | 1272 | dounlimit(Char **v, struct command *t) | |
1273 | { | 1273 | { | |
1274 | const struct limits *lp; | 1274 | const struct limits *lp; | |
1275 | int lerr; | 1275 | int lerr; | |
1276 | Char hard; | 1276 | Char hard; | |
1277 | 1277 | |||
1278 | lerr = 0; | 1278 | lerr = 0; | |
1279 | hard = 0; | 1279 | hard = 0; | |
1280 | v++; | 1280 | v++; | |
1281 | if (*v && eq(*v, STRmh)) { | 1281 | if (*v && eq(*v, STRmh)) { | |
1282 | hard = 1; | 1282 | hard = 1; | |
1283 | v++; | 1283 | v++; | |
1284 | } | 1284 | } | |
1285 | if (*v == 0) { | 1285 | if (*v == 0) { | |
1286 | for (lp = limits; lp->limconst >= 0; lp++) | 1286 | for (lp = limits; lp->limconst >= 0; lp++) | |
1287 | if (setlim(lp, hard, (RLIM_TYPE)RLIM_INFINITY) < 0) | 1287 | if (setlim(lp, hard, (RLIM_TYPE)RLIM_INFINITY) < 0) | |
1288 | lerr++; | 1288 | lerr++; | |
1289 | if (lerr) | 1289 | if (lerr) | |
1290 | stderror(ERR_SILENT); | 1290 | stderror(ERR_SILENT); | |
1291 | return; | 1291 | return; | |
1292 | } | 1292 | } | |
1293 | while (*v) { | 1293 | while (*v) { | |
1294 | lp = findlim(*v++); | 1294 | lp = findlim(*v++); | |
1295 | if (setlim(lp, hard, (RLIM_TYPE)RLIM_INFINITY) < 0) | 1295 | if (setlim(lp, hard, (RLIM_TYPE)RLIM_INFINITY) < 0) | |
1296 | stderror(ERR_SILENT); | 1296 | stderror(ERR_SILENT); | |
1297 | } | 1297 | } | |
1298 | } | 1298 | } | |
1299 | 1299 | |||
1300 | static int | 1300 | static int | |
1301 | setlim(const struct limits *lp, Char hard, RLIM_TYPE limit) | 1301 | setlim(const struct limits *lp, Char hard, RLIM_TYPE limit) | |
1302 | { | 1302 | { | |
1303 | struct rlimit rlim; | 1303 | struct rlimit rlim; | |
1304 | 1304 | |||
1305 | (void)getrlimit(lp->limconst, &rlim); | 1305 | (void)getrlimit(lp->limconst, &rlim); | |
1306 | 1306 | |||
1307 | if (hard) | 1307 | if (hard) | |
1308 | rlim.rlim_max = limit; | 1308 | rlim.rlim_max = limit; | |
1309 | else if (limit == RLIM_INFINITY && geteuid() != 0) | 1309 | else if (limit == RLIM_INFINITY && geteuid() != 0) | |
1310 | rlim.rlim_cur = rlim.rlim_max; | 1310 | rlim.rlim_cur = rlim.rlim_max; | |
1311 | else | 1311 | else | |
1312 | rlim.rlim_cur = limit; | 1312 | rlim.rlim_cur = limit; | |
1313 | 1313 | |||
1314 | if (rlim.rlim_max < rlim.rlim_cur) | 1314 | if (rlim.rlim_max < rlim.rlim_cur) | |
1315 | rlim.rlim_max = rlim.rlim_cur; | 1315 | rlim.rlim_max = rlim.rlim_cur; | |
1316 | 1316 | |||
1317 | if (setrlimit(lp->limconst, &rlim) < 0) { | 1317 | if (setrlimit(lp->limconst, &rlim) < 0) { | |
1318 | (void)fprintf(csherr, "%s: %s: Can't %s%s limit (%s)\n", bname, | 1318 | (void)fprintf(csherr, "%s: %s: Can't %s%s limit (%s)\n", bname, | |
1319 | lp->limname, limit == RLIM_INFINITY ? "remove" : "set", | 1319 | lp->limname, limit == RLIM_INFINITY ? "remove" : "set", | |
1320 | hard ? " hard" : "", strerror(errno)); | 1320 | hard ? " hard" : "", strerror(errno)); | |
1321 | return (-1); | 1321 | return (-1); | |
1322 | } | 1322 | } | |
1323 | return (0); | 1323 | return (0); | |
1324 | } | 1324 | } | |
1325 | 1325 | |||
1326 | void | 1326 | void | |
1327 | /*ARGSUSED*/ | 1327 | /*ARGSUSED*/ | |
1328 | dosuspend(Char **v, struct command *t) | 1328 | dosuspend(Char **v, struct command *t) | |
1329 | { | 1329 | { | |
1330 | int ctpgrp; | 1330 | int ctpgrp; | |
1331 | void (*old)(int); | 1331 | void (*old)(int); | |
1332 | 1332 | |||
1333 | if (loginsh) | 1333 | if (loginsh) | |
1334 | stderror(ERR_SUSPLOG); | 1334 | stderror(ERR_SUSPLOG); | |
1335 | untty(); | 1335 | untty(); | |
1336 | 1336 | |||
1337 | old = signal(SIGTSTP, SIG_DFL); | 1337 | old = signal(SIGTSTP, SIG_DFL); | |
1338 | (void)kill(0, SIGTSTP); | 1338 | (void)kill(0, SIGTSTP); | |
1339 | /* the shell stops here */ | 1339 | /* the shell stops here */ | |
1340 | (void)signal(SIGTSTP, old); | 1340 | (void)signal(SIGTSTP, old); | |
1341 | 1341 | |||
1342 | if (tpgrp != -1) { | 1342 | if (tpgrp != -1) { | |
1343 | retry: | 1343 | retry: | |
1344 | ctpgrp = tcgetpgrp(FSHTTY); | 1344 | ctpgrp = tcgetpgrp(FSHTTY); | |
1345 | if (ctpgrp != opgrp) { | 1345 | if (ctpgrp != opgrp) { | |
1346 | old = signal(SIGTTIN, SIG_DFL); | 1346 | old = signal(SIGTTIN, SIG_DFL); | |
1347 | (void)kill(0, SIGTTIN); | 1347 | (void)kill(0, SIGTTIN); | |
1348 | (void)signal(SIGTTIN, old); | 1348 | (void)signal(SIGTTIN, old); | |
1349 | goto retry; | 1349 | goto retry; | |
1350 | } | 1350 | } | |
1351 | (void)setpgid(0, shpgrp); | 1351 | (void)setpgid(0, shpgrp); | |
1352 | (void)tcsetpgrp(FSHTTY, shpgrp); | 1352 | (void)tcsetpgrp(FSHTTY, shpgrp); | |
1353 | } | 1353 | } | |
1354 | } | 1354 | } | |
1355 | 1355 | |||
1356 | /* This is the dreaded EVAL built-in. | 1356 | /* This is the dreaded EVAL built-in. | |
1357 | * If you don't fiddle with file descriptors, and reset didfds, | 1357 | * If you don't fiddle with file descriptors, and reset didfds, | |
1358 | * this command will either ignore redirection inside or outside | 1358 | * this command will either ignore redirection inside or outside | |
1359 | * its arguments, e.g. eval "date >x" vs. eval "date" >x | 1359 | * its arguments, e.g. eval "date >x" vs. eval "date" >x | |
1360 | * The stuff here seems to work, but I did it by trial and error rather | 1360 | * The stuff here seems to work, but I did it by trial and error rather | |
1361 | * than really knowing what was going on. If tpgrp is zero, we are | 1361 | * than really knowing what was going on. If tpgrp is zero, we are | |
1362 | * probably a background eval, e.g. "eval date &", and we want to | 1362 | * probably a background eval, e.g. "eval date &", and we want to | |
1363 | * make sure that any processes we start stay in our pgrp. | 1363 | * make sure that any processes we start stay in our pgrp. | |
1364 | * This is also the case for "time eval date" -- stay in same pgrp. | 1364 | * This is also the case for "time eval date" -- stay in same pgrp. | |
1365 | * Otherwise, under stty tostop, processes will stop in the wrong | 1365 | * Otherwise, under stty tostop, processes will stop in the wrong | |
1366 | * pgrp, with no way for the shell to get them going again. -IAN! | 1366 | * pgrp, with no way for the shell to get them going again. -IAN! | |
1367 | */ | 1367 | */ | |
1368 | static Char **gv = NULL; | 1368 | static Char **gv = NULL; | |
1369 | 1369 | |||
1370 | void | 1370 | void | |
1371 | /*ARGSUSED*/ | 1371 | /*ARGSUSED*/ | |
1372 | doeval(Char **v, struct command *t) | 1372 | doeval(Char **v, struct command *t) | |
1373 | { | 1373 | { | |
1374 | jmp_buf osetexit; | 1374 | jmp_buf osetexit; | |
1375 | Char *oevalp, **oevalvec, **savegv; | 1375 | Char *oevalp, **oevalvec, **savegv; | |
1376 | int my_reenter, odidfds, oSHERR, oSHIN, oSHOUT, saveERR, saveIN, saveOUT; | 1376 | int my_reenter, odidfds, oSHERR, oSHIN, oSHOUT, saveERR, saveIN, saveOUT; | |
1377 | 1377 | |||
1378 | savegv = gv; | 1378 | savegv = gv; | |
1379 | UNREGISTER(v); | 1379 | UNREGISTER(v); | |
1380 | 1380 | |||
1381 | oevalvec = evalvec; | 1381 | oevalvec = evalvec; | |
1382 | oevalp = evalp; | 1382 | oevalp = evalp; | |
1383 | odidfds = didfds; | 1383 | odidfds = didfds; | |
1384 | oSHIN = SHIN; | 1384 | oSHIN = SHIN; | |
1385 | oSHOUT = SHOUT; | 1385 | oSHOUT = SHOUT; | |
1386 | oSHERR = SHERR; | 1386 | oSHERR = SHERR; | |
1387 | 1387 | |||
1388 | v++; | 1388 | v++; | |
1389 | if (*v == 0) | 1389 | if (*v == 0) | |
1390 | return; | 1390 | return; | |
1391 | gflag = 0, tglob(v); | 1391 | gflag = 0, tglob(v); | |
1392 | if (gflag) { | 1392 | if (gflag) { | |
1393 | gv = v = globall(v); | 1393 | gv = v = globall(v); | |
1394 | gargv = 0; | 1394 | gargv = 0; | |
1395 | if (v == 0) | 1395 | if (v == 0) | |
1396 | stderror(ERR_NOMATCH); | 1396 | stderror(ERR_NOMATCH); | |
1397 | v = copyblk(v); | 1397 | v = copyblk(v); | |
1398 | } | 1398 | } | |
1399 | else { | 1399 | else { | |
1400 | gv = NULL; | 1400 | gv = NULL; | |
1401 | v = copyblk(v); | 1401 | v = copyblk(v); | |
1402 | trim(v); | 1402 | trim(v); | |
1403 | } | 1403 | } | |
1404 | 1404 | |||
1405 | saveIN = dcopy(SHIN, -1); | 1405 | saveIN = dcopy(SHIN, -1); | |
1406 | saveOUT = dcopy(SHOUT, -1); | 1406 | saveOUT = dcopy(SHOUT, -1); | |
1407 | saveERR = dcopy(SHERR, -1); | 1407 | saveERR = dcopy(SHERR, -1); | |
1408 | 1408 | |||
1409 | getexit(osetexit); | 1409 | getexit(osetexit); | |
1410 | 1410 | |||
1411 | if ((my_reenter = setexit()) == 0) { | 1411 | if ((my_reenter = setexit()) == 0) { | |
1412 | evalvec = v; | 1412 | evalvec = v; | |
1413 | evalp = 0; | 1413 | evalp = 0; | |
1414 | SHIN = dcopy(0, -1); | 1414 | SHIN = dcopy(0, -1); | |
1415 | SHOUT = dcopy(1, -1); | 1415 | SHOUT = dcopy(1, -1); | |
1416 | SHERR = dcopy(2, -1); | 1416 | SHERR = dcopy(2, -1); | |
1417 | didfds = 0; | 1417 | didfds = 0; | |
1418 | process(0); | 1418 | process(0); | |
1419 | } | 1419 | } | |
1420 | 1420 | |||
1421 | evalvec = oevalvec; | 1421 | evalvec = oevalvec; | |
1422 | evalp = oevalp; | 1422 | evalp = oevalp; | |
1423 | doneinp = 0; | 1423 | doneinp = 0; | |
1424 | didfds = odidfds; | 1424 | didfds = odidfds; | |
1425 | if (SHIN != -1) | 1425 | if (SHIN != -1) | |
1426 | (void)close(SHIN); | 1426 | (void)close(SHIN); | |
1427 | if (SHOUT != -1) | 1427 | if (SHOUT != -1) | |
1428 | (void)close(SHOUT); | 1428 | (void)close(SHOUT); | |
1429 | if (SHERR != -1) | 1429 | if (SHERR != -1) | |
1430 | (void)close(SHERR); | 1430 | (void)close(SHERR); | |
1431 | SHIN = dmove(saveIN, oSHIN); | 1431 | SHIN = dmove(saveIN, oSHIN); | |
1432 | SHOUT = dmove(saveOUT, oSHOUT); | 1432 | SHOUT = dmove(saveOUT, oSHOUT); | |
1433 | SHERR = dmove(saveERR, oSHERR); | 1433 | SHERR = dmove(saveERR, oSHERR); | |
1434 | if (gv) | 1434 | if (gv) | |
1435 | blkfree(gv), gv = NULL; | 1435 | blkfree(gv), gv = NULL; | |
1436 | resexit(osetexit); | 1436 | resexit(osetexit); | |
1437 | gv = savegv; | 1437 | gv = savegv; | |
1438 | if (my_reenter) | 1438 | if (my_reenter) | |
1439 | stderror(ERR_SILENT); | 1439 | stderror(ERR_SILENT); | |
1440 | } | 1440 | } | |
1441 | 1441 | |||
1442 | void | 1442 | void | |
1443 | /*ARGSUSED*/ | 1443 | /*ARGSUSED*/ | |
1444 | doprintf(Char **v, struct command *t) | 1444 | doprintf(Char **v, struct command *t) | |
1445 | { | 1445 | { | |
1446 | char **c; | 1446 | char **c; | |
1447 | int ret; | 1447 | int ret; | |
1448 | 1448 | |||
1449 | ret = progprintf(blklen(v), c = short2blk(v)); | 1449 | ret = progprintf(blklen(v), c = short2blk(v)); | |
1450 | (void)fflush(cshout); | 1450 | (void)fflush(cshout); | |
1451 | (void)fflush(csherr); | 1451 | (void)fflush(csherr); | |
1452 | 1452 | |||
1453 | blkfree((Char **)c); | 1453 | blkfree((Char **)c); | |
1454 | if (ret) | 1454 | if (ret) | |
1455 | stderror(ERR_SILENT); | 1455 | stderror(ERR_SILENT); | |
1456 | } | 1456 | } |
--- src/bin/csh/glob.c 2019/01/05 16:56:25 1.31
+++ src/bin/csh/glob.c 2024/04/24 15:49:03 1.32
@@ -1,937 +1,937 @@ | @@ -1,937 +1,937 @@ | |||
1 | /* $NetBSD: glob.c,v 1.31 2019/01/05 16:56:25 christos Exp $ */ | 1 | /* $NetBSD: glob.c,v 1.32 2024/04/24 15:49:03 nia Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1980, 1991, 1993 | 4 | * Copyright (c) 1980, 1991, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the University nor the names of its contributors | 15 | * 3. Neither the name of the University nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | #if 0 | 34 | #if 0 | |
35 | static char sccsid[] = "@(#)glob.c 8.1 (Berkeley) 5/31/93"; | 35 | static char sccsid[] = "@(#)glob.c 8.1 (Berkeley) 5/31/93"; | |
36 | #else | 36 | #else | |
37 | __RCSID("$NetBSD: glob.c,v 1.31 2019/01/05 16:56:25 christos Exp $"); | 37 | __RCSID("$NetBSD: glob.c,v 1.32 2024/04/24 15:49:03 nia Exp $"); | |
38 | #endif | 38 | #endif | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #include <sys/param.h> | 41 | #include <sys/param.h> | |
42 | 42 | |||
43 | #include <errno.h> | 43 | #include <errno.h> | |
44 | #include <glob.h> | 44 | #include <glob.h> | |
45 | #include <stdarg.h> | 45 | #include <stdarg.h> | |
46 | #include <stddef.h> | 46 | #include <stddef.h> | |
47 | #include <stdlib.h> | 47 | #include <stdlib.h> | |
48 | #include <string.h> | 48 | #include <string.h> | |
49 | #include <unistd.h> | 49 | #include <unistd.h> | |
50 | 50 | |||
51 | #include "csh.h" | 51 | #include "csh.h" | |
52 | #include "extern.h" | 52 | #include "extern.h" | |
53 | 53 | |||
54 | static int noglob; | 54 | static int noglob; | |
55 | static int gargsiz, pargsiz; | 55 | static int gargsiz, pargsiz; | |
56 | 56 | |||
57 | /* | 57 | /* | |
58 | * Values for gflag | 58 | * Values for gflag | |
59 | */ | 59 | */ | |
60 | #define G_NONE 0 /* No globbing needed */ | 60 | #define G_NONE 0 /* No globbing needed */ | |
61 | #define G_GLOB 1 /* string contains *?[] characters */ | 61 | #define G_GLOB 1 /* string contains *?[] characters */ | |
62 | #define G_CSH 2 /* string contains ~`{ characters */ | 62 | #define G_CSH 2 /* string contains ~`{ characters */ | |
63 | 63 | |||
64 | #define GLOBSPACE 100 /* Alloc increment */ | 64 | #define GLOBSPACE 100 /* Alloc increment */ | |
65 | 65 | |||
66 | #define LBRC '{' | 66 | #define LBRC '{' | |
67 | #define RBRC '}' | 67 | #define RBRC '}' | |
68 | #define LBRK '[' | 68 | #define LBRK '[' | |
69 | #define RBRK ']' | 69 | #define RBRK ']' | |
70 | #define EOS '\0' | 70 | #define EOS '\0' | |
71 | 71 | |||
72 | Char **gargv = NULL; | 72 | Char **gargv = NULL; | |
73 | Char **pargv = NULL; | 73 | Char **pargv = NULL; | |
74 | long gargc = 0; | 74 | long gargc = 0; | |
75 | long pargc = 0; | 75 | long pargc = 0; | |
76 | 76 | |||
77 | /* | 77 | /* | |
78 | * globbing is now done in two stages. In the first pass we expand | 78 | * globbing is now done in two stages. In the first pass we expand | |
79 | * csh globbing idioms ~`{ and then we proceed doing the normal | 79 | * csh globbing idioms ~`{ and then we proceed doing the normal | |
80 | * globbing if needed ?*[ | 80 | * globbing if needed ?*[ | |
81 | * | 81 | * | |
82 | * Csh type globbing is handled in globexpand() and the rest is | 82 | * Csh type globbing is handled in globexpand() and the rest is | |
83 | * handled in glob() which is part of the 4.4BSD libc. | 83 | * handled in glob() which is part of the 4.4BSD libc. | |
84 | * | 84 | * | |
85 | */ | 85 | */ | |
86 | static Char *globtilde(Char **, Char *); | 86 | static Char *globtilde(Char **, Char *); | |
87 | static Char *handleone(Char *, Char **, int); | 87 | static Char *handleone(Char *, Char **, int); | |
88 | static Char **libglob(Char **); | 88 | static Char **libglob(Char **); | |
89 | static Char **globexpand(Char **); | 89 | static Char **globexpand(Char **); | |
90 | static int globbrace(Char *, Char *, Char ***); | 90 | static int globbrace(Char *, Char *, Char ***); | |
91 | static void expbrace(Char ***, Char ***, size_t); | 91 | static void expbrace(Char ***, Char ***, size_t); | |
92 | static int pmatch(const Char *, const Char *); | 92 | static int pmatch(const Char *, const Char *); | |
93 | static void pword(void); | 93 | static void pword(void); | |
94 | static void psave(int); | 94 | static void psave(int); | |
95 | static void backeval(Char *, int); | 95 | static void backeval(Char *, int); | |
96 | 96 | |||
97 | static Char * | 97 | static Char * | |
98 | globtilde(Char **nv, Char *s) | 98 | globtilde(Char **nv, Char *s) | |
99 | { | 99 | { | |
100 | Char gbuf[MAXPATHLEN], *b, *e, *gstart, *u; | 100 | Char gbuf[MAXPATHLEN], *b, *e, *gstart, *u; | |
101 | 101 | |||
102 | gstart = gbuf; | 102 | gstart = gbuf; | |
103 | *gstart++ = *s++; | 103 | *gstart++ = *s++; | |
104 | u = s; | 104 | u = s; | |
105 | for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; | 105 | for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; | |
106 | *s && *s != '/' && *s != ':' && b < e; | 106 | *s && *s != '/' && *s != ':' && b < e; | |
107 | *b++ = *s++) | 107 | *b++ = *s++) | |
108 | continue; | 108 | continue; | |
109 | *b = EOS; | 109 | *b = EOS; | |
110 | if (gethdir(gstart)) { | 110 | if (gethdir(gstart)) { | |
111 | blkfree(nv); | 111 | blkfree(nv); | |
112 | if (*gstart) | 112 | if (*gstart) | |
113 | stderror(ERR_UNKUSER, vis_str(gstart)); | 113 | stderror(ERR_UNKUSER, vis_str(gstart)); | |
114 | else | 114 | else | |
115 | stderror(ERR_NOHOME); | 115 | stderror(ERR_NOHOME); | |
116 | } | 116 | } | |
117 | b = &gstart[Strlen(gstart)]; | 117 | b = &gstart[Strlen(gstart)]; | |
118 | while (*s) | 118 | while (*s) | |
119 | *b++ = *s++; | 119 | *b++ = *s++; | |
120 | *b = EOS; | 120 | *b = EOS; | |
121 | --u; | 121 | --u; | |
122 | free(u); | 122 | free(u); | |
123 | return (Strsave(gstart)); | 123 | return (Strsave(gstart)); | |
124 | } | 124 | } | |
125 | 125 | |||
126 | static int | 126 | static int | |
127 | globbrace(Char *s, Char *p, Char ***bl) | 127 | globbrace(Char *s, Char *p, Char ***bl) | |
128 | { | 128 | { | |
129 | Char gbuf[MAXPATHLEN]; | 129 | Char gbuf[MAXPATHLEN]; | |
130 | Char *lm, *pe, *pl, *pm, **nv, **vl; | 130 | Char *lm, *pe, *pl, *pm, **nv, **vl; | |
131 | int i, len, size; | 131 | int i, len, size; | |
132 | 132 | |||
133 | size = GLOBSPACE; | 133 | size = GLOBSPACE; | |
134 | nv = vl = xmalloc(sizeof(Char *) * (size_t)size); | 134 | nv = vl = xreallocarray(NULL, sizeof(Char *), (size_t)size); | |
135 | *vl = NULL; | 135 | *vl = NULL; | |
136 | len = 0; | 136 | len = 0; | |
137 | /* copy part up to the brace */ | 137 | /* copy part up to the brace */ | |
138 | for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) | 138 | for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) | |
139 | continue; | 139 | continue; | |
140 | 140 | |||
141 | /* check for balanced braces */ | 141 | /* check for balanced braces */ | |
142 | for (i = 0, pe = ++p; *pe; pe++) | 142 | for (i = 0, pe = ++p; *pe; pe++) | |
143 | if (*pe == LBRK) { | 143 | if (*pe == LBRK) { | |
144 | /* Ignore everything between [] */ | 144 | /* Ignore everything between [] */ | |
145 | for (++pe; *pe != RBRK && *pe != EOS; pe++) | 145 | for (++pe; *pe != RBRK && *pe != EOS; pe++) | |
146 | continue; | 146 | continue; | |
147 | if (*pe == EOS) { | 147 | if (*pe == EOS) { | |
148 | blkfree(nv); | 148 | blkfree(nv); | |
149 | return (-RBRK); | 149 | return (-RBRK); | |
150 | } | 150 | } | |
151 | } | 151 | } | |
152 | else if (*pe == LBRC) | 152 | else if (*pe == LBRC) | |
153 | i++; | 153 | i++; | |
154 | else if (*pe == RBRC) { | 154 | else if (*pe == RBRC) { | |
155 | if (i == 0) | 155 | if (i == 0) | |
156 | break; | 156 | break; | |
157 | i--; | 157 | i--; | |
158 | } | 158 | } | |
159 | 159 | |||
160 | if (i != 0 || *pe == '\0') { | 160 | if (i != 0 || *pe == '\0') { | |
161 | blkfree(nv); | 161 | blkfree(nv); | |
162 | return (-RBRC); | 162 | return (-RBRC); | |
163 | } | 163 | } | |
164 | 164 | |||
165 | for (i = 0, pl = pm = p; pm <= pe; pm++) | 165 | for (i = 0, pl = pm = p; pm <= pe; pm++) | |
166 | switch (*pm) { | 166 | switch (*pm) { | |
167 | case LBRK: | 167 | case LBRK: | |
168 | for (++pm; *pm != RBRK && *pm != EOS; pm++) | 168 | for (++pm; *pm != RBRK && *pm != EOS; pm++) | |
169 | continue; | 169 | continue; | |
170 | if (*pm == EOS) { | 170 | if (*pm == EOS) { | |
171 | *vl = NULL; | 171 | *vl = NULL; | |
172 | blkfree(nv); | 172 | blkfree(nv); | |
173 | return (-RBRK); | 173 | return (-RBRK); | |
174 | } | 174 | } | |
175 | break; | 175 | break; | |
176 | case LBRC: | 176 | case LBRC: | |
177 | i++; | 177 | i++; | |
178 | break; | 178 | break; | |
179 | case RBRC: | 179 | case RBRC: | |
180 | if (i) { | 180 | if (i) { | |
181 | i--; | 181 | i--; | |
182 | break; | 182 | break; | |
183 | } | 183 | } | |
184 | /* FALLTHROUGH */ | 184 | /* FALLTHROUGH */ | |
185 | case ',': | 185 | case ',': | |
186 | if (i && *pm == ',') | 186 | if (i && *pm == ',') | |
187 | break; | 187 | break; | |
188 | else { | 188 | else { | |
189 | Char savec = *pm; | 189 | Char savec = *pm; | |
190 | 190 | |||
191 | *pm = EOS; | 191 | *pm = EOS; | |
192 | (void)Strcpy(lm, pl); | 192 | (void)Strcpy(lm, pl); | |
193 | (void)Strcat(gbuf, pe + 1); | 193 | (void)Strcat(gbuf, pe + 1); | |
194 | *pm = savec; | 194 | *pm = savec; | |
195 | *vl++ = Strsave(gbuf); | 195 | *vl++ = Strsave(gbuf); | |
196 | len++; | 196 | len++; | |
197 | pl = pm + 1; | 197 | pl = pm + 1; | |
198 | if (vl == &nv[size]) { | 198 | if (vl == &nv[size]) { | |
199 | size += GLOBSPACE; | 199 | size += GLOBSPACE; | |
200 | nv = xrealloc(nv, (size_t)size * sizeof(Char *)); | 200 | nv = xreallocarray(nv, (size_t)size, sizeof(Char *)); | |
201 | vl = &nv[size - GLOBSPACE]; | 201 | vl = &nv[size - GLOBSPACE]; | |
202 | } | 202 | } | |
203 | } | 203 | } | |
204 | break; | 204 | break; | |
205 | default: | 205 | default: | |
206 | break; | 206 | break; | |
207 | } | 207 | } | |
208 | *vl = NULL; | 208 | *vl = NULL; | |
209 | *bl = nv; | 209 | *bl = nv; | |
210 | return (len); | 210 | return (len); | |
211 | } | 211 | } | |
212 | 212 | |||
213 | static void | 213 | static void | |
214 | expbrace(Char ***nvp, Char ***elp, size_t size) | 214 | expbrace(Char ***nvp, Char ***elp, size_t size) | |
215 | { | 215 | { | |
216 | Char **ex, **nv, *s, **vl; | 216 | Char **ex, **nv, *s, **vl; | |
217 | 217 | |||
218 | vl = nv = *nvp; | 218 | vl = nv = *nvp; | |
219 | if (elp != NULL) | 219 | if (elp != NULL) | |
220 | ex = *elp; | 220 | ex = *elp; | |
221 | else | 221 | else | |
222 | for (ex = vl; *ex; ex++) | 222 | for (ex = vl; *ex; ex++) | |
223 | continue; | 223 | continue; | |
224 | 224 | |||
225 | for (s = *vl; s; s = *++vl) { | 225 | for (s = *vl; s; s = *++vl) { | |
226 | Char *b, **bp, **vp; | 226 | Char *b, **bp, **vp; | |
227 | 227 | |||
228 | /* leave {} untouched for find */ | 228 | /* leave {} untouched for find */ | |
229 | if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) | 229 | if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) | |
230 | continue; | 230 | continue; | |
231 | if ((b = Strchr(s, '{')) != NULL) { | 231 | if ((b = Strchr(s, '{')) != NULL) { | |
232 | Char **bl; | 232 | Char **bl; | |
233 | int len; | 233 | int len; | |
234 | 234 | |||
235 | if ((len = globbrace(s, b, &bl)) < 0) { | 235 | if ((len = globbrace(s, b, &bl)) < 0) { | |
236 | free(nv); | 236 | free(nv); | |
237 | stderror(ERR_MISSING, -len); | 237 | stderror(ERR_MISSING, -len); | |
238 | } | 238 | } | |
239 | free(s); | 239 | free(s); | |
240 | if (len == 1) { | 240 | if (len == 1) { | |
241 | *vl-- = *bl; | 241 | *vl-- = *bl; | |
242 | free(bl); | 242 | free(bl); | |
243 | continue; | 243 | continue; | |
244 | } | 244 | } | |
245 | len = blklen(bl); | 245 | len = blklen(bl); | |
246 | if (&ex[len] >= &nv[size]) { | 246 | if (&ex[len] >= &nv[size]) { | |
247 | ptrdiff_t l, e; | 247 | ptrdiff_t l, e; | |
248 | 248 | |||
249 | l = &ex[len] - &nv[size]; | 249 | l = &ex[len] - &nv[size]; | |
250 | size += (size_t)(GLOBSPACE > l ? GLOBSPACE : l); | 250 | size += (size_t)(GLOBSPACE > l ? GLOBSPACE : l); | |
251 | l = vl - nv; | 251 | l = vl - nv; | |
252 | e = ex - nv; | 252 | e = ex - nv; | |
253 | nv = xrealloc(nv, (size_t)size * sizeof(Char *)); | 253 | nv = xreallocarray(nv, size, sizeof(Char *)); | |
254 | vl = nv + l; | 254 | vl = nv + l; | |
255 | ex = nv + e; | 255 | ex = nv + e; | |
256 | } | 256 | } | |
257 | vp = vl--; | 257 | vp = vl--; | |
258 | *vp = *bl; | 258 | *vp = *bl; | |
259 | len--; | 259 | len--; | |
260 | for (bp = ex; bp != vp; bp--) | 260 | for (bp = ex; bp != vp; bp--) | |
261 | bp[len] = *bp; | 261 | bp[len] = *bp; | |
262 | ex += len; | 262 | ex += len; | |
263 | vp++; | 263 | vp++; | |
264 | for (bp = bl + 1; *bp; *vp++ = *bp++) | 264 | for (bp = bl + 1; *bp; *vp++ = *bp++) | |
265 | continue; | 265 | continue; | |
266 | free(bl); | 266 | free(bl); | |
267 | } | 267 | } | |
268 | 268 | |||
269 | } | 269 | } | |
270 | if (elp != NULL) | 270 | if (elp != NULL) | |
271 | *elp = ex; | 271 | *elp = ex; | |
272 | *nvp = nv; | 272 | *nvp = nv; | |
273 | } | 273 | } | |
274 | 274 | |||
275 | static Char ** | 275 | static Char ** | |
276 | globexpand(Char **v) | 276 | globexpand(Char **v) | |
277 | { | 277 | { | |
278 | Char **ex, **nv, *s, **vl; | 278 | Char **ex, **nv, *s, **vl; | |
279 | size_t size; | 279 | size_t size; | |
280 | 280 | |||
281 | size = GLOBSPACE; | 281 | size = GLOBSPACE; | |
282 | nv = vl = xmalloc(sizeof(Char *) * size); | 282 | nv = vl = xreallocarray(NULL, sizeof(Char *), size); | |
283 | *vl = NULL; | 283 | *vl = NULL; | |
284 | 284 | |||
285 | /* | 285 | /* | |
286 | * Step 1: expand backquotes. | 286 | * Step 1: expand backquotes. | |
287 | */ | 287 | */ | |
288 | while ((s = *v++) != NULL) { | 288 | while ((s = *v++) != NULL) { | |
289 | if (Strchr(s, '`')) { | 289 | if (Strchr(s, '`')) { | |
290 | int i; | 290 | int i; | |
291 | 291 | |||
292 | (void) dobackp(s, 0); | 292 | (void) dobackp(s, 0); | |
293 | for (i = 0; i < pargc; i++) { | 293 | for (i = 0; i < pargc; i++) { | |
294 | *vl++ = pargv[i]; | 294 | *vl++ = pargv[i]; | |
295 | if (vl == &nv[size]) { | 295 | if (vl == &nv[size]) { | |
296 | size += GLOBSPACE; | 296 | size += GLOBSPACE; | |
297 | nv = xrealloc(nv, (size_t)size * sizeof(Char *)); | 297 | nv = xreallocarray(nv, size, sizeof(Char *)); | |
298 | vl = &nv[size - GLOBSPACE]; | 298 | vl = &nv[size - GLOBSPACE]; | |
299 | } | 299 | } | |
300 | } | 300 | } | |
301 | free(pargv); | 301 | free(pargv); | |
302 | pargv = NULL; | 302 | pargv = NULL; | |
303 | } | 303 | } | |
304 | else { | 304 | else { | |
305 | *vl++ = Strsave(s); | 305 | *vl++ = Strsave(s); | |
306 | if (vl == &nv[size]) { | 306 | if (vl == &nv[size]) { | |
307 | size += GLOBSPACE; | 307 | size += GLOBSPACE; | |
308 | nv = xrealloc(nv, size * sizeof(Char *)); | 308 | nv = xreallocarray(nv, size, sizeof(Char *)); | |
309 | vl = &nv[size - GLOBSPACE]; | 309 | vl = &nv[size - GLOBSPACE]; | |
310 | } | 310 | } | |
311 | } | 311 | } | |
312 | } | 312 | } | |
313 | *vl = NULL; | 313 | *vl = NULL; | |
314 | 314 | |||
315 | if (noglob) | 315 | if (noglob) | |
316 | return (nv); | 316 | return (nv); | |
317 | 317 | |||
318 | /* | 318 | /* | |
319 | * Step 2: expand braces | 319 | * Step 2: expand braces | |
320 | */ | 320 | */ | |
321 | ex = vl; | 321 | ex = vl; | |
322 | expbrace(&nv, &ex, size); | 322 | expbrace(&nv, &ex, size); | |
323 | 323 | |||
324 | /* | 324 | /* | |
325 | * Step 3: expand ~ | 325 | * Step 3: expand ~ | |
326 | */ | 326 | */ | |
327 | vl = nv; | 327 | vl = nv; | |
328 | for (s = *vl; s; s = *++vl) | 328 | for (s = *vl; s; s = *++vl) | |
329 | if (*s == '~') | 329 | if (*s == '~') | |
330 | *vl = globtilde(nv, s); | 330 | *vl = globtilde(nv, s); | |
331 | vl = nv; | 331 | vl = nv; | |
332 | return (vl); | 332 | return (vl); | |
333 | } | 333 | } | |
334 | 334 | |||
335 | static Char * | 335 | static Char * | |
336 | handleone(Char *str, Char **vl, int action) | 336 | handleone(Char *str, Char **vl, int action) | |
337 | { | 337 | { | |
338 | Char *cp, **vlp; | 338 | Char *cp, **vlp; | |
339 | 339 | |||
340 | vlp = vl; | 340 | vlp = vl; | |
341 | switch (action) { | 341 | switch (action) { | |
342 | case G_ERROR: | 342 | case G_ERROR: | |
343 | setname(vis_str(str)); | 343 | setname(vis_str(str)); | |
344 | blkfree(vl); | 344 | blkfree(vl); | |
345 | stderror(ERR_NAME | ERR_AMBIG); | 345 | stderror(ERR_NAME | ERR_AMBIG); | |
346 | /* NOTREACHED */ | 346 | /* NOTREACHED */ | |
347 | case G_APPEND: | 347 | case G_APPEND: | |
348 | trim(vlp); | 348 | trim(vlp); | |
349 | str = Strsave(*vlp++); | 349 | str = Strsave(*vlp++); | |
350 | do { | 350 | do { | |
351 | cp = Strspl(str, STRspace); | 351 | cp = Strspl(str, STRspace); | |
352 | free(str); | 352 | free(str); | |
353 | str = Strspl(cp, *vlp); | 353 | str = Strspl(cp, *vlp); | |
354 | free(cp); | 354 | free(cp); | |
355 | } | 355 | } | |
356 | while (*++vlp); | 356 | while (*++vlp); | |
357 | blkfree(vl); | 357 | blkfree(vl); | |
358 | break; | 358 | break; | |
359 | case G_IGNORE: | 359 | case G_IGNORE: | |
360 | str = Strsave(strip(*vlp)); | 360 | str = Strsave(strip(*vlp)); | |
361 | blkfree(vl); | 361 | blkfree(vl); | |
362 | break; | 362 | break; | |
363 | default: | 363 | default: | |
364 | break; | 364 | break; | |
365 | } | 365 | } | |
366 | return (str); | 366 | return (str); | |
367 | } | 367 | } | |
368 | 368 | |||
369 | static Char ** | 369 | static Char ** | |
370 | libglob(Char **vl) | 370 | libglob(Char **vl) | |
371 | { | 371 | { | |
372 | glob_t globv; | 372 | glob_t globv; | |
373 | char *ptr; | 373 | char *ptr; | |
374 | int gflgs, magic, match, nonomatch; | 374 | int gflgs, magic, match, nonomatch; | |
375 | 375 | |||
376 | gflgs = GLOB_NOMAGIC; | 376 | gflgs = GLOB_NOMAGIC; | |
377 | magic = 0; | 377 | magic = 0; | |
378 | match = 0; | 378 | match = 0; | |
379 | nonomatch = adrof(STRnonomatch) != 0; | 379 | nonomatch = adrof(STRnonomatch) != 0; | |
380 | 380 | |||
381 | if (!vl || !vl[0]) | 381 | if (!vl || !vl[0]) | |
382 | return (vl); | 382 | return (vl); | |
383 | 383 | |||
384 | globv.gl_offs = 0; | 384 | globv.gl_offs = 0; | |
385 | globv.gl_pathv = 0; | 385 | globv.gl_pathv = 0; | |
386 | globv.gl_pathc = 0; | 386 | globv.gl_pathc = 0; | |
387 | 387 | |||
388 | if (nonomatch) | 388 | if (nonomatch) | |
389 | gflgs |= GLOB_NOCHECK; | 389 | gflgs |= GLOB_NOCHECK; | |
390 | 390 | |||
391 | do { | 391 | do { | |
392 | ptr = short2qstr(*vl); | 392 | ptr = short2qstr(*vl); | |
393 | switch (glob(ptr, gflgs, 0, &globv)) { | 393 | switch (glob(ptr, gflgs, 0, &globv)) { | |
394 | case GLOB_ABORTED: | 394 | case GLOB_ABORTED: | |
395 | setname(vis_str(*vl)); | 395 | setname(vis_str(*vl)); | |
396 | stderror(ERR_NAME | ERR_GLOB); | 396 | stderror(ERR_NAME | ERR_GLOB); | |
397 | /* NOTREACHED */ | 397 | /* NOTREACHED */ | |
398 | case GLOB_NOSPACE: | 398 | case GLOB_NOSPACE: | |
399 | stderror(ERR_NOMEM); | 399 | stderror(ERR_NOMEM); | |
400 | /* NOTREACHED */ | 400 | /* NOTREACHED */ | |
401 | default: | 401 | default: | |
402 | break; | 402 | break; | |
403 | } | 403 | } | |
404 | if (globv.gl_flags & GLOB_MAGCHAR) { | 404 | if (globv.gl_flags & GLOB_MAGCHAR) { | |
405 | match |= (globv.gl_matchc != 0); | 405 | match |= (globv.gl_matchc != 0); | |
406 | magic = 1; | 406 | magic = 1; | |
407 | } | 407 | } | |
408 | gflgs |= GLOB_APPEND; | 408 | gflgs |= GLOB_APPEND; | |
409 | } | 409 | } | |
410 | while (*++vl); | 410 | while (*++vl); | |
411 | vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? | 411 | vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? | |
412 | NULL : blk2short(globv.gl_pathv); | 412 | NULL : blk2short(globv.gl_pathv); | |
413 | globfree(&globv); | 413 | globfree(&globv); | |
414 | return (vl); | 414 | return (vl); | |
415 | } | 415 | } | |
416 | 416 | |||
417 | Char * | 417 | Char * | |
418 | globone(Char *str, int action) | 418 | globone(Char *str, int action) | |
419 | { | 419 | { | |
420 | Char *v[2], **vl, **vo; | 420 | Char *v[2], **vl, **vo; | |
421 | int gflg; | 421 | int gflg; | |
422 | 422 | |||
423 | noglob = adrof(STRnoglob) != 0; | 423 | noglob = adrof(STRnoglob) != 0; | |
424 | gflag = 0; | 424 | gflag = 0; | |
425 | v[0] = str; | 425 | v[0] = str; | |
426 | v[1] = 0; | 426 | v[1] = 0; | |
427 | tglob(v); | 427 | tglob(v); | |
428 | gflg = gflag; | 428 | gflg = gflag; | |
429 | if (gflg == G_NONE) | 429 | if (gflg == G_NONE) | |
430 | return (strip(Strsave(str))); | 430 | return (strip(Strsave(str))); | |
431 | 431 | |||
432 | if (gflg & G_CSH) { | 432 | if (gflg & G_CSH) { | |
433 | /* | 433 | /* | |
434 | * Expand back-quote, tilde and brace | 434 | * Expand back-quote, tilde and brace | |
435 | */ | 435 | */ | |
436 | vo = globexpand(v); | 436 | vo = globexpand(v); | |
437 | if (noglob || (gflg & G_GLOB) == 0) { | 437 | if (noglob || (gflg & G_GLOB) == 0) { | |
438 | if (vo[0] == NULL) { | 438 | if (vo[0] == NULL) { | |
439 | free(vo); | 439 | free(vo); | |
440 | return (Strsave(STRNULL)); | 440 | return (Strsave(STRNULL)); | |
441 | } | 441 | } | |
442 | if (vo[1] != NULL) | 442 | if (vo[1] != NULL) | |
443 | return (handleone(str, vo, action)); | 443 | return (handleone(str, vo, action)); | |
444 | else { | 444 | else { | |
445 | str = strip(vo[0]); | 445 | str = strip(vo[0]); | |
446 | free(vo); | 446 | free(vo); | |
447 | return (str); | 447 | return (str); | |
448 | } | 448 | } | |
449 | } | 449 | } | |
450 | } | 450 | } | |
451 | else if (noglob || (gflg & G_GLOB) == 0) | 451 | else if (noglob || (gflg & G_GLOB) == 0) | |
452 | return (strip(Strsave(str))); | 452 | return (strip(Strsave(str))); | |
453 | else | 453 | else | |
454 | vo = v; | 454 | vo = v; | |
455 | 455 | |||
456 | vl = libglob(vo); | 456 | vl = libglob(vo); | |
457 | if ((gflg & G_CSH) && vl != vo) | 457 | if ((gflg & G_CSH) && vl != vo) | |
458 | blkfree(vo); | 458 | blkfree(vo); | |
459 | if (vl == NULL) { | 459 | if (vl == NULL) { | |
460 | setname(vis_str(str)); | 460 | setname(vis_str(str)); | |
461 | stderror(ERR_NAME | ERR_NOMATCH); | 461 | stderror(ERR_NAME | ERR_NOMATCH); | |
462 | } | 462 | } | |
463 | if (vl[0] == NULL) { | 463 | if (vl[0] == NULL) { | |
464 | free(vl); | 464 | free(vl); | |
465 | return (Strsave(STRNULL)); | 465 | return (Strsave(STRNULL)); | |
466 | } | 466 | } | |
467 | if (vl[1] != NULL) | 467 | if (vl[1] != NULL) | |
468 | return (handleone(str, vl, action)); | 468 | return (handleone(str, vl, action)); | |
469 | else { | 469 | else { | |
470 | str = strip(*vl); | 470 | str = strip(*vl); | |
471 | free(vl); | 471 | free(vl); | |
472 | return (str); | 472 | return (str); | |
473 | } | 473 | } | |
474 | } | 474 | } | |
475 | 475 | |||
476 | Char ** | 476 | Char ** | |
477 | globall(Char **v) | 477 | globall(Char **v) | |
478 | { | 478 | { | |
479 | Char **vl, **vo; | 479 | Char **vl, **vo; | |
480 | int gflg; | 480 | int gflg; | |
481 | 481 | |||
482 | gflg = gflag; | 482 | gflg = gflag; | |
483 | if (!v || !v[0]) { | 483 | if (!v || !v[0]) { | |
484 | gargv = saveblk(v); | 484 | gargv = saveblk(v); | |
485 | gargc = blklen(gargv); | 485 | gargc = blklen(gargv); | |
486 | return (gargv); | 486 | return (gargv); | |
487 | } | 487 | } | |
488 | 488 | |||
489 | noglob = adrof(STRnoglob) != 0; | 489 | noglob = adrof(STRnoglob) != 0; | |
490 | 490 | |||
491 | if (gflg & G_CSH) | 491 | if (gflg & G_CSH) | |
492 | /* | 492 | /* | |
493 | * Expand back-quote, tilde and brace | 493 | * Expand back-quote, tilde and brace | |
494 | */ | 494 | */ | |
495 | vl = vo = globexpand(v); | 495 | vl = vo = globexpand(v); | |
496 | else | 496 | else | |
497 | vl = vo = saveblk(v); | 497 | vl = vo = saveblk(v); | |
498 | 498 | |||
499 | if (!noglob && (gflg & G_GLOB)) { | 499 | if (!noglob && (gflg & G_GLOB)) { | |
500 | vl = libglob(vo); | 500 | vl = libglob(vo); | |
501 | if ((gflg & G_CSH) && vl != vo) | 501 | if ((gflg & G_CSH) && vl != vo) | |
502 | blkfree(vo); | 502 | blkfree(vo); | |
503 | } | 503 | } | |
504 | else | 504 | else | |
505 | trim(vl); | 505 | trim(vl); | |
506 | 506 | |||
507 | gargc = vl ? blklen(vl) : 0; | 507 | gargc = vl ? blklen(vl) : 0; | |
508 | return (gargv = vl); | 508 | return (gargv = vl); | |
509 | } | 509 | } | |
510 | 510 | |||
511 | void | 511 | void | |
512 | ginit(void) | 512 | ginit(void) | |
513 | { | 513 | { | |
514 | gargsiz = GLOBSPACE; | 514 | gargsiz = GLOBSPACE; | |
515 | gargv = xmalloc(sizeof(Char *) * (size_t)gargsiz); | 515 | gargv = xreallocarray(NULL, sizeof(Char *), (size_t)gargsiz); | |
516 | gargv[0] = 0; | 516 | gargv[0] = 0; | |
517 | gargc = 0; | 517 | gargc = 0; | |
518 | } | 518 | } | |
519 | 519 | |||
520 | void | 520 | void | |
521 | rscan(Char **t, void (*f)(int)) | 521 | rscan(Char **t, void (*f)(int)) | |
522 | { | 522 | { | |
523 | Char *p; | 523 | Char *p; | |
524 | 524 | |||
525 | while ((p = *t++) != NULL) | 525 | while ((p = *t++) != NULL) | |
526 | while (*p) | 526 | while (*p) | |
527 | (*f) (*p++); | 527 | (*f) (*p++); | |
528 | } | 528 | } | |
529 | 529 | |||
530 | void | 530 | void | |
531 | trim(Char **t) | 531 | trim(Char **t) | |
532 | { | 532 | { | |
533 | Char *p; | 533 | Char *p; | |
534 | 534 | |||
535 | while ((p = *t++) != NULL) | 535 | while ((p = *t++) != NULL) | |
536 | while (*p) | 536 | while (*p) | |
537 | *p++ &= TRIM; | 537 | *p++ &= TRIM; | |
538 | } | 538 | } | |
539 | 539 | |||
540 | void | 540 | void | |
541 | tglob(Char **t) | 541 | tglob(Char **t) | |
542 | { | 542 | { | |
543 | Char *p, c; | 543 | Char *p, c; | |
544 | 544 | |||
545 | while ((p = *t++) != NULL) { | 545 | while ((p = *t++) != NULL) { | |
546 | if (*p == '~' || *p == '=') | 546 | if (*p == '~' || *p == '=') | |
547 | gflag |= G_CSH; | 547 | gflag |= G_CSH; | |
548 | else if (*p == '{' && | 548 | else if (*p == '{' && | |
549 | (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) | 549 | (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) | |
550 | continue; | 550 | continue; | |
551 | while ((c = *p++) != '\0') { | 551 | while ((c = *p++) != '\0') { | |
552 | /* | 552 | /* | |
553 | * eat everything inside the matching backquotes | 553 | * eat everything inside the matching backquotes | |
554 | */ | 554 | */ | |
555 | if (c == '`') { | 555 | if (c == '`') { | |
556 | gflag |= G_CSH; | 556 | gflag |= G_CSH; | |
557 | while (*p && *p != '`') | 557 | while (*p && *p != '`') | |
558 | if (*p++ == '\\') { | 558 | if (*p++ == '\\') { | |
559 | if (*p) /* Quoted chars */ | 559 | if (*p) /* Quoted chars */ | |
560 | p++; | 560 | p++; | |
561 | else | 561 | else | |
562 | break; | 562 | break; | |
563 | } | 563 | } | |
564 | if (*p) /* The matching ` */ | 564 | if (*p) /* The matching ` */ | |
565 | p++; | 565 | p++; | |
566 | else | 566 | else | |
567 | break; | 567 | break; | |
568 | } | 568 | } | |
569 | else if (c == '{') | 569 | else if (c == '{') | |
570 | gflag |= G_CSH; | 570 | gflag |= G_CSH; | |
571 | else if (isglob(c)) | 571 | else if (isglob(c)) | |
572 | gflag |= G_GLOB; | 572 | gflag |= G_GLOB; | |
573 | } | 573 | } | |
574 | } | 574 | } | |
575 | } | 575 | } | |
576 | 576 | |||
577 | /* | 577 | /* | |
578 | * Command substitute cp. If literal, then this is a substitution from a | 578 | * Command substitute cp. If literal, then this is a substitution from a | |
579 | * << redirection, and so we should not crunch blanks and tabs, separating | 579 | * << redirection, and so we should not crunch blanks and tabs, separating | |
580 | * words only at newlines. | 580 | * words only at newlines. | |
581 | */ | 581 | */ | |
582 | Char ** | 582 | Char ** | |
583 | dobackp(Char *cp, int literal) | 583 | dobackp(Char *cp, int literal) | |
584 | { | 584 | { | |
585 | Char word[MAXPATHLEN], *ep, *lp, *rp; | 585 | Char word[MAXPATHLEN], *ep, *lp, *rp; | |
586 | 586 | |||
587 | if (pargv) { | 587 | if (pargv) { | |
588 | #ifdef notdef | 588 | #ifdef notdef | |
589 | abort(); | 589 | abort(); | |
590 | #endif | 590 | #endif | |
591 | blkfree(pargv); | 591 | blkfree(pargv); | |
592 | } | 592 | } | |
593 | pargsiz = GLOBSPACE; | 593 | pargsiz = GLOBSPACE; | |
594 | pargv = xmalloc(sizeof(Char *) * (size_t)pargsiz); | 594 | pargv = xreallocarray(NULL, sizeof(Char *), (size_t)pargsiz); | |
595 | pargv[0] = NULL; | 595 | pargv[0] = NULL; | |
596 | pargcp = pargs = word; | 596 | pargcp = pargs = word; | |
597 | pargc = 0; | 597 | pargc = 0; | |
598 | pnleft = MAXPATHLEN - 4; | 598 | pnleft = MAXPATHLEN - 4; | |
599 | for (;;) { | 599 | for (;;) { | |
600 | for (lp = cp; *lp != '`'; lp++) { | 600 | for (lp = cp; *lp != '`'; lp++) { | |
601 | if (*lp == 0) { | 601 | if (*lp == 0) { | |
602 | if (pargcp != pargs) | 602 | if (pargcp != pargs) | |
603 | pword(); | 603 | pword(); | |
604 | return (pargv); | 604 | return (pargv); | |
605 | } | 605 | } | |
606 | psave(*lp); | 606 | psave(*lp); | |
607 | } | 607 | } | |
608 | lp++; | 608 | lp++; | |
609 | for (rp = lp; *rp && *rp != '`'; rp++) | 609 | for (rp = lp; *rp && *rp != '`'; rp++) | |
610 | if (*rp == '\\') { | 610 | if (*rp == '\\') { | |
611 | rp++; | 611 | rp++; | |
612 | if (!*rp) | 612 | if (!*rp) | |
613 | goto oops; | 613 | goto oops; | |
614 | } | 614 | } | |
615 | if (!*rp) { | 615 | if (!*rp) { | |
616 | oops: | 616 | oops: | |
617 | stderror(ERR_UNMATCHED, '`'); | 617 | stderror(ERR_UNMATCHED, '`'); | |
618 | } | 618 | } | |
619 | ep = Strsave(lp); | 619 | ep = Strsave(lp); | |
620 | ep[rp - lp] = 0; | 620 | ep[rp - lp] = 0; | |
621 | backeval(ep, literal); | 621 | backeval(ep, literal); | |
622 | cp = rp + 1; | 622 | cp = rp + 1; | |
623 | } | 623 | } | |
624 | } | 624 | } | |
625 | 625 | |||
626 | static void | 626 | static void | |
627 | backeval(Char *cp, int literal) | 627 | backeval(Char *cp, int literal) | |
628 | { | 628 | { | |
629 | struct command faket; | 629 | struct command faket; | |
630 | char tibuf[BUFSIZE]; | 630 | char tibuf[BUFSIZE]; | |
631 | Char ibuf[BUFSIZE], *fakecom[2], *ip; | 631 | Char ibuf[BUFSIZE], *fakecom[2], *ip; | |
632 | int pvec[2], c, quoted; | 632 | int pvec[2], c, quoted; | |
633 | ssize_t icnt; | 633 | ssize_t icnt; | |
634 | int hadnl; | 634 | int hadnl; | |
635 | 635 | |||
636 | hadnl = 0; | 636 | hadnl = 0; | |
637 | icnt = 0; | 637 | icnt = 0; | |
638 | quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; | 638 | quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; | |
639 | faket.t_dtyp = NODE_COMMAND; | 639 | faket.t_dtyp = NODE_COMMAND; | |
640 | faket.t_dflg = 0; | 640 | faket.t_dflg = 0; | |
641 | faket.t_dlef = 0; | 641 | faket.t_dlef = 0; | |
642 | faket.t_drit = 0; | 642 | faket.t_drit = 0; | |
643 | faket.t_dspr = 0; | 643 | faket.t_dspr = 0; | |
644 | faket.t_dcom = fakecom; | 644 | faket.t_dcom = fakecom; | |
645 | fakecom[0] = STRfakecom1; | 645 | fakecom[0] = STRfakecom1; | |
646 | fakecom[1] = 0; | 646 | fakecom[1] = 0; | |
647 | 647 | |||
648 | /* | 648 | /* | |
649 | * We do the psave job to temporarily change the current job so that the | 649 | * We do the psave job to temporarily change the current job so that the | |
650 | * following fork is considered a separate job. This is so that when | 650 | * following fork is considered a separate job. This is so that when | |
651 | * backquotes are used in a builtin function that calls glob the "current | 651 | * backquotes are used in a builtin function that calls glob the "current | |
652 | * job" is not corrupted. We only need one level of pushed jobs as long as | 652 | * job" is not corrupted. We only need one level of pushed jobs as long as | |
653 | * we are sure to fork here. | 653 | * we are sure to fork here. | |
654 | */ | 654 | */ | |
655 | psavejob(); | 655 | psavejob(); | |
656 | 656 | |||
657 | /* | 657 | /* | |
658 | * It would be nicer if we could integrate this redirection more with the | 658 | * It would be nicer if we could integrate this redirection more with the | |
659 | * routines in sh.sem.c by doing a fake execute on a builtin function that | 659 | * routines in sh.sem.c by doing a fake execute on a builtin function that | |
660 | * was piped out. | 660 | * was piped out. | |
661 | */ | 661 | */ | |
662 | mypipe(pvec); | 662 | mypipe(pvec); | |
663 | if (pfork(&faket, -1) == 0) { | 663 | if (pfork(&faket, -1) == 0) { | |
664 | struct wordent fparaml; | 664 | struct wordent fparaml; | |
665 | struct command *t; | 665 | struct command *t; | |
666 | 666 | |||
667 | (void)close(pvec[0]); | 667 | (void)close(pvec[0]); | |
668 | (void)dmove(pvec[1], 1); | 668 | (void)dmove(pvec[1], 1); | |
669 | (void)dmove(SHERR, 2); | 669 | (void)dmove(SHERR, 2); | |
670 | initdesc(); | 670 | initdesc(); | |
671 | /* | 671 | /* | |
672 | * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, | 672 | * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, | |
673 | * posted to comp.bugs.4bsd 12 Sep. 1989. | 673 | * posted to comp.bugs.4bsd 12 Sep. 1989. | |
674 | */ | 674 | */ | |
675 | if (pargv) /* mg, 21.dec.88 */ | 675 | if (pargv) /* mg, 21.dec.88 */ | |
676 | blkfree(pargv), pargv = 0, pargsiz = 0; | 676 | blkfree(pargv), pargv = 0, pargsiz = 0; | |
677 | /* mg, 21.dec.88 */ | 677 | /* mg, 21.dec.88 */ | |
678 | arginp = cp; | 678 | arginp = cp; | |
679 | for (arginp = cp; *cp; cp++) { | 679 | for (arginp = cp; *cp; cp++) { | |
680 | *cp &= TRIM; | 680 | *cp &= TRIM; | |
681 | if (*cp == '\n' || *cp == '\r') | 681 | if (*cp == '\n' || *cp == '\r') | |
682 | *cp = ';'; | 682 | *cp = ';'; | |
683 | } | 683 | } | |
684 | 684 | |||
685 | /* | 685 | /* | |
686 | * In the child ``forget'' everything about current aliases or | 686 | * In the child ``forget'' everything about current aliases or | |
687 | * eval vectors. | 687 | * eval vectors. | |
688 | */ | 688 | */ | |
689 | alvec = NULL; | 689 | alvec = NULL; | |
690 | evalvec = NULL; | 690 | evalvec = NULL; | |
691 | alvecp = NULL; | 691 | alvecp = NULL; | |
692 | evalp = NULL; | 692 | evalp = NULL; | |
693 | (void) lex(&fparaml); | 693 | (void) lex(&fparaml); | |
694 | if (seterr) | 694 | if (seterr) | |
695 | stderror(ERR_OLD); | 695 | stderror(ERR_OLD); | |
696 | alias(&fparaml); | 696 | alias(&fparaml); | |
697 | t = syntax(fparaml.next, &fparaml, 0); | 697 | t = syntax(fparaml.next, &fparaml, 0); | |
698 | if (seterr) | 698 | if (seterr) | |
699 | stderror(ERR_OLD); | 699 | stderror(ERR_OLD); | |
700 | if (t) | 700 | if (t) | |
701 | t->t_dflg |= F_NOFORK; | 701 | t->t_dflg |= F_NOFORK; | |
702 | (void)signal(SIGTSTP, SIG_IGN); | 702 | (void)signal(SIGTSTP, SIG_IGN); | |
703 | (void)signal(SIGTTIN, SIG_IGN); | 703 | (void)signal(SIGTTIN, SIG_IGN); | |
704 | (void)signal(SIGTTOU, SIG_IGN); | 704 | (void)signal(SIGTTOU, SIG_IGN); | |
705 | execute(t, -1, NULL, NULL); | 705 | execute(t, -1, NULL, NULL); | |
706 | exitstat(); | 706 | exitstat(); | |
707 | } | 707 | } | |
708 | free(cp); | 708 | free(cp); | |
709 | (void)close(pvec[1]); | 709 | (void)close(pvec[1]); | |
710 | c = 0; | 710 | c = 0; | |
711 | ip = NULL; | 711 | ip = NULL; | |
712 | do { | 712 | do { | |
713 | int cnt; | 713 | int cnt; | |
714 | 714 | |||
715 | cnt = 0; | 715 | cnt = 0; | |
716 | 716 | |||
717 | for (;;) { | 717 | for (;;) { | |
718 | if (icnt == 0) { | 718 | if (icnt == 0) { | |
719 | int i; | 719 | int i; | |
720 | 720 | |||
721 | ip = ibuf; | 721 | ip = ibuf; | |
722 | do | 722 | do | |
723 | icnt = read(pvec[0], tibuf, BUFSIZE); | 723 | icnt = read(pvec[0], tibuf, BUFSIZE); | |
724 | while (icnt == -1 && errno == EINTR); | 724 | while (icnt == -1 && errno == EINTR); | |
725 | if (icnt <= 0) { | 725 | if (icnt <= 0) { | |
726 | c = -1; | 726 | c = -1; | |
727 | break; | 727 | break; | |
728 | } | 728 | } | |
729 | for (i = 0; i < icnt; i++) | 729 | for (i = 0; i < icnt; i++) | |
730 | ip[i] = (unsigned char) tibuf[i]; | 730 | ip[i] = (unsigned char) tibuf[i]; | |
731 | } | 731 | } | |
732 | if (hadnl) | 732 | if (hadnl) | |
733 | break; | 733 | break; | |
734 | --icnt; | 734 | --icnt; | |
735 | c = (*ip++ & TRIM); | 735 | c = (*ip++ & TRIM); | |
736 | if (c == 0) | 736 | if (c == 0) | |
737 | break; | 737 | break; | |
738 | if (c == '\n') { | 738 | if (c == '\n') { | |
739 | /* | 739 | /* | |
740 | * Continue around the loop one more time, so that we can eat | 740 | * Continue around the loop one more time, so that we can eat | |
741 | * the last newline without terminating this word. | 741 | * the last newline without terminating this word. | |
742 | */ | 742 | */ | |
743 | hadnl = 1; | 743 | hadnl = 1; | |
744 | continue; | 744 | continue; | |
745 | } | 745 | } | |
746 | if (!quoted && (c == ' ' || c == '\t')) | 746 | if (!quoted && (c == ' ' || c == '\t')) | |
747 | break; | 747 | break; | |
748 | cnt++; | 748 | cnt++; | |
749 | psave(c | quoted); | 749 | psave(c | quoted); | |
750 | } | 750 | } | |
751 | /* | 751 | /* | |
752 | * Unless at end-of-file, we will form a new word here if there were | 752 | * Unless at end-of-file, we will form a new word here if there were | |
753 | * characters in the word, or in any case when we take text literally. | 753 | * characters in the word, or in any case when we take text literally. | |
754 | * If we didn't make empty words here when literal was set then we | 754 | * If we didn't make empty words here when literal was set then we | |
755 | * would lose blank lines. | 755 | * would lose blank lines. | |
756 | */ | 756 | */ | |
757 | if (c != -1 && (cnt || literal)) | 757 | if (c != -1 && (cnt || literal)) | |
758 | pword(); | 758 | pword(); | |
759 | hadnl = 0; | 759 | hadnl = 0; | |
760 | } while (c >= 0); | 760 | } while (c >= 0); | |
761 | (void)close(pvec[0]); | 761 | (void)close(pvec[0]); | |
762 | pwait(); | 762 | pwait(); | |
763 | prestjob(); | 763 | prestjob(); | |
764 | } | 764 | } | |
765 | 765 | |||
766 | static void | 766 | static void | |
767 | psave(int c) | 767 | psave(int c) | |
768 | { | 768 | { | |
769 | if (--pnleft <= 0) | 769 | if (--pnleft <= 0) | |
770 | stderror(ERR_WTOOLONG); | 770 | stderror(ERR_WTOOLONG); | |
771 | *pargcp++ = (Char)c; | 771 | *pargcp++ = (Char)c; | |
772 | } | 772 | } | |
773 | 773 | |||
774 | static void | 774 | static void | |
775 | pword(void) | 775 | pword(void) | |
776 | { | 776 | { | |
777 | psave(0); | 777 | psave(0); | |
778 | if (pargc == pargsiz - 1) { | 778 | if (pargc == pargsiz - 1) { | |
779 | pargsiz += GLOBSPACE; | 779 | pargsiz += GLOBSPACE; | |
780 | pargv = xrealloc(pargv, (size_t)pargsiz * sizeof(Char *)); | 780 | pargv = xreallocarray(pargv, (size_t)pargsiz, sizeof(Char *)); | |
781 | } | 781 | } | |
782 | pargv[pargc++] = Strsave(pargs); | 782 | pargv[pargc++] = Strsave(pargs); | |
783 | pargv[pargc] = NULL; | 783 | pargv[pargc] = NULL; | |
784 | pargcp = pargs; | 784 | pargcp = pargs; | |
785 | pnleft = MAXPATHLEN - 4; | 785 | pnleft = MAXPATHLEN - 4; | |
786 | } | 786 | } | |
787 | 787 | |||
788 | int | 788 | int | |
789 | Gmatch(Char *string, Char *pattern) | 789 | Gmatch(Char *string, Char *pattern) | |
790 | { | 790 | { | |
791 | Char **blk, **p; | 791 | Char **blk, **p; | |
792 | int gpol, gres; | 792 | int gpol, gres; | |
793 | 793 | |||
794 | gpol = 1; | 794 | gpol = 1; | |
795 | gres = 0; | 795 | gres = 0; | |
796 | 796 | |||
797 | if (*pattern == '^') { | 797 | if (*pattern == '^') { | |
798 | gpol = 0; | 798 | gpol = 0; | |
799 | pattern++; | 799 | pattern++; | |
800 | } | 800 | } | |
801 | 801 | |||
802 | blk = xmalloc(GLOBSPACE * sizeof(Char *)); | 802 | blk = xreallocarray(NULL, GLOBSPACE, sizeof(Char *)); | |
803 | blk[0] = Strsave(pattern); | 803 | blk[0] = Strsave(pattern); | |
804 | blk[1] = NULL; | 804 | blk[1] = NULL; | |
805 | 805 | |||
806 | expbrace(&blk, NULL, GLOBSPACE); | 806 | expbrace(&blk, NULL, GLOBSPACE); | |
807 | 807 | |||
808 | for (p = blk; *p; p++) | 808 | for (p = blk; *p; p++) | |
809 | gres |= pmatch(string, *p); | 809 | gres |= pmatch(string, *p); | |
810 | 810 | |||
811 | blkfree(blk); | 811 | blkfree(blk); | |
812 | return(gres == gpol); | 812 | return(gres == gpol); | |
813 | } | 813 | } | |
814 | 814 | |||
815 | static int | 815 | static int | |
816 | pmatch(const Char *name, const Char *pat) | 816 | pmatch(const Char *name, const Char *pat) | |
817 | { | 817 | { | |
818 | int match, negate_range; | 818 | int match, negate_range; | |
819 | Char patc, namec, c; | 819 | Char patc, namec, c; | |
820 | const Char *nameNext, *nameStart, *nameEnd, *patNext; | 820 | const Char *nameNext, *nameStart, *nameEnd, *patNext; | |
821 | 821 | |||
822 | nameNext = nameStart = name; | 822 | nameNext = nameStart = name; | |
823 | patNext = pat; | 823 | patNext = pat; | |
824 | nameEnd = NULL; | 824 | nameEnd = NULL; | |
825 | 825 | |||
826 | for (;;) { | 826 | for (;;) { | |
827 | namec = *name & TRIM; | 827 | namec = *name & TRIM; | |
828 | if (namec == 0) | 828 | if (namec == 0) | |
829 | nameEnd = name; | 829 | nameEnd = name; | |
830 | patc = *pat; | 830 | patc = *pat; | |
831 | switch (patc) { | 831 | switch (patc) { | |
832 | case 0: | 832 | case 0: | |
833 | if (namec == 0) | 833 | if (namec == 0) | |
834 | return 1; | 834 | return 1; | |
835 | break; | 835 | break; | |
836 | case '?': | 836 | case '?': | |
837 | if (namec == 0) | 837 | if (namec == 0) | |
838 | break; | 838 | break; | |
839 | pat++; | 839 | pat++; | |
840 | name++; | 840 | name++; | |
841 | continue; | 841 | continue; | |
842 | case '*': | 842 | case '*': | |
843 | while ((pat[1] & TRIM) == '*') | 843 | while ((pat[1] & TRIM) == '*') | |
844 | pat++; | 844 | pat++; | |
845 | patNext = pat; | 845 | patNext = pat; | |
846 | nameNext = name + 1; | 846 | nameNext = name + 1; | |
847 | pat++; | 847 | pat++; | |
848 | continue; | 848 | continue; | |
849 | case '[': | 849 | case '[': | |
850 | match = 0; | 850 | match = 0; | |
851 | if (namec == 0) | 851 | if (namec == 0) | |
852 | break; | 852 | break; | |
853 | pat++; | 853 | pat++; | |
854 | name++; | 854 | name++; | |
855 | if ((negate_range = (*pat == '^')) != 0) | 855 | if ((negate_range = (*pat == '^')) != 0) | |
856 | pat++; | 856 | pat++; | |
857 | while ((c = *pat++) != ']') { | 857 | while ((c = *pat++) != ']') { | |
858 | c &= TRIM; | 858 | c &= TRIM; | |
859 | if (*pat == '-') { | 859 | if (*pat == '-') { | |
860 | if (c <= namec && namec <= (pat[1] & TRIM)) | 860 | if (c <= namec && namec <= (pat[1] & TRIM)) | |
861 | match = 1; | 861 | match = 1; | |
862 | pat += 2; | 862 | pat += 2; | |
863 | } else if (c == namec) | 863 | } else if (c == namec) | |
864 | match = 1; | 864 | match = 1; | |
865 | else if (c == 0) | 865 | else if (c == 0) | |
866 | stderror(ERR_NAME | ERR_MISSING, ']'); | 866 | stderror(ERR_NAME | ERR_MISSING, ']'); | |
867 | } | 867 | } | |
868 | if (match == negate_range) | 868 | if (match == negate_range) | |
869 | break; | 869 | break; | |
870 | continue; | 870 | continue; | |
871 | default: | 871 | default: | |
872 | if ((patc & TRIM) != namec) | 872 | if ((patc & TRIM) != namec) | |
873 | break; | 873 | break; | |
874 | pat++; | 874 | pat++; | |
875 | name++; | 875 | name++; | |
876 | continue; | 876 | continue; | |
877 | } | 877 | } | |
878 | if (nameNext != nameStart && (nameEnd == NULL || nameNext <= nameEnd)) { | 878 | if (nameNext != nameStart && (nameEnd == NULL || nameNext <= nameEnd)) { | |
879 | pat = patNext; | 879 | pat = patNext; | |
880 | name = nameNext; | 880 | name = nameNext; | |
881 | continue; | 881 | continue; | |
882 | } | 882 | } | |
883 | return 0; | 883 | return 0; | |
884 | } | 884 | } | |
885 | } | 885 | } | |
886 | 886 | |||
887 | void | 887 | void | |
888 | Gcat(Char *s1, Char *s2) | 888 | Gcat(Char *s1, Char *s2) | |
889 | { | 889 | { | |
890 | Char *p, *q; | 890 | Char *p, *q; | |
891 | ptrdiff_t n; | 891 | ptrdiff_t n; | |
892 | 892 | |||
893 | for (p = s1; *p++;) | 893 | for (p = s1; *p++;) | |
894 | continue; | 894 | continue; | |
895 | for (q = s2; *q++;) | 895 | for (q = s2; *q++;) | |
896 | continue; | 896 | continue; | |
897 | n = (p - s1) + (q - s2) - 1; | 897 | n = (p - s1) + (q - s2) - 1; | |
898 | if (++gargc >= gargsiz) { | 898 | if (++gargc >= gargsiz) { | |
899 | gargsiz += GLOBSPACE; | 899 | gargsiz += GLOBSPACE; | |
900 | gargv = xrealloc(gargv, (size_t)gargsiz * sizeof(Char *)); | 900 | gargv = xreallocarray(gargv, (size_t)gargsiz, sizeof(Char *)); | |
901 | } | 901 | } | |
902 | gargv[gargc] = 0; | 902 | gargv[gargc] = 0; | |
903 | p = gargv[gargc - 1] = xmalloc((size_t)n * sizeof(Char)); | 903 | p = gargv[gargc - 1] = xreallocarray(NULL, (size_t)n, sizeof(Char)); | |
904 | for (q = s1; (*p++ = *q++) != '\0';) | 904 | for (q = s1; (*p++ = *q++) != '\0';) | |
905 | continue; | 905 | continue; | |
906 | for (p--, q = s2; (*p++ = *q++) != '\0';) | 906 | for (p--, q = s2; (*p++ = *q++) != '\0';) | |
907 | continue; | 907 | continue; | |
908 | } | 908 | } | |
909 | 909 | |||
910 | #ifdef FILEC | 910 | #ifdef FILEC | |
911 | int | 911 | int | |
912 | sortscmp(const void *va, const void *vb) | 912 | sortscmp(const void *va, const void *vb) | |
913 | { | 913 | { | |
914 | #if defined(NLS) && !defined(NOSTRCOLL) | 914 | #if defined(NLS) && !defined(NOSTRCOLL) | |
915 | char buf[2048]; | 915 | char buf[2048]; | |
916 | #endif | 916 | #endif | |
917 | const Char * const *a = va; | 917 | const Char * const *a = va; | |
918 | const Char * const *b = vb; | 918 | const Char * const *b = vb; | |
919 | 919 | |||
920 | if (!a) /* check for NULL */ | 920 | if (!a) /* check for NULL */ | |
921 | return (b ? 1 : 0); | 921 | return (b ? 1 : 0); | |
922 | if (!b) | 922 | if (!b) | |
923 | return -1; | 923 | return -1; | |
924 | 924 | |||
925 | if (!*a) /* check for NULL */ | 925 | if (!*a) /* check for NULL */ | |
926 | return *b ? 1 : 0; | 926 | return *b ? 1 : 0; | |
927 | if (!*b) | 927 | if (!*b) | |
928 | return (-1); | 928 | return (-1); | |
929 | 929 | |||
930 | #if defined(NLS) && !defined(NOSTRCOLL) | 930 | #if defined(NLS) && !defined(NOSTRCOLL) | |
931 | (void)strcpy(buf, short2str(*a)); | 931 | (void)strcpy(buf, short2str(*a)); | |
932 | return (int)strcoll(buf, short2str(*b)); | 932 | return (int)strcoll(buf, short2str(*b)); | |
933 | #else | 933 | #else | |
934 | return (int)Strcmp(*a, *b); | 934 | return (int)Strcmp(*a, *b); | |
935 | #endif | 935 | #endif | |
936 | } | 936 | } | |
937 | #endif /* FILEC */ | 937 | #endif /* FILEC */ |
--- src/bin/csh/misc.c 2019/01/05 16:54:00 1.22
+++ src/bin/csh/misc.c 2024/04/24 15:49:03 1.23
@@ -1,407 +1,407 @@ | @@ -1,407 +1,407 @@ | |||
1 | /* $NetBSD: misc.c,v 1.22 2019/01/05 16:54:00 christos Exp $ */ | 1 | /* $NetBSD: misc.c,v 1.23 2024/04/24 15:49:03 nia Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1980, 1991, 1993 | 4 | * Copyright (c) 1980, 1991, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the University nor the names of its contributors | 15 | * 3. Neither the name of the University nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | #if 0 | 34 | #if 0 | |
35 | static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 5/31/93"; | 35 | static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 5/31/93"; | |
36 | #else | 36 | #else | |
37 | __RCSID("$NetBSD: misc.c,v 1.22 2019/01/05 16:54:00 christos Exp $"); | 37 | __RCSID("$NetBSD: misc.c,v 1.23 2024/04/24 15:49:03 nia Exp $"); | |
38 | #endif | 38 | #endif | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #include <sys/param.h> | 41 | #include <sys/param.h> | |
42 | 42 | |||
43 | #include <stdarg.h> | 43 | #include <stdarg.h> | |
44 | #include <stdlib.h> | 44 | #include <stdlib.h> | |
45 | #include <string.h> | 45 | #include <string.h> | |
46 | #include <unistd.h> | 46 | #include <unistd.h> | |
47 | #include <fcntl.h> | 47 | #include <fcntl.h> | |
48 | 48 | |||
49 | #include "csh.h" | 49 | #include "csh.h" | |
50 | #include "extern.h" | 50 | #include "extern.h" | |
51 | 51 | |||
52 | static int renum(int, int); | 52 | static int renum(int, int); | |
53 | 53 | |||
54 | int | 54 | int | |
55 | any(const char *s, int c) | 55 | any(const char *s, int c) | |
56 | { | 56 | { | |
57 | if (!s) | 57 | if (!s) | |
58 | return (0); /* Check for nil pointer */ | 58 | return (0); /* Check for nil pointer */ | |
59 | while (*s) | 59 | while (*s) | |
60 | if (*s++ == c) | 60 | if (*s++ == c) | |
61 | return (1); | 61 | return (1); | |
62 | return (0); | 62 | return (0); | |
63 | } | 63 | } | |
64 | 64 | |||
65 | char * | 65 | char * | |
66 | strsave(const char *s) | 66 | strsave(const char *s) | |
67 | { | 67 | { | |
68 | const char *n; | 68 | const char *n; | |
69 | char *p, *r; | 69 | char *p, *r; | |
70 | 70 | |||
71 | if (s == NULL) | 71 | if (s == NULL) | |
72 | s = ""; | 72 | s = ""; | |
73 | for (n = s; *n++;) | 73 | for (n = s; *n++;) | |
74 | continue; | 74 | continue; | |
75 | r = p = xmalloc((size_t)(n - s) * sizeof(*p)); | 75 | r = p = xreallocarray(NULL, (size_t)(n - s), sizeof(*p)); | |
76 | while ((*p++ = *s++) != '\0') | 76 | while ((*p++ = *s++) != '\0') | |
77 | continue; | 77 | continue; | |
78 | return (r); | 78 | return (r); | |
79 | } | 79 | } | |
80 | 80 | |||
81 | Char ** | 81 | Char ** | |
82 | blkend(Char **up) | 82 | blkend(Char **up) | |
83 | { | 83 | { | |
84 | while (*up) | 84 | while (*up) | |
85 | up++; | 85 | up++; | |
86 | return (up); | 86 | return (up); | |
87 | } | 87 | } | |
88 | 88 | |||
89 | 89 | |||
90 | void | 90 | void | |
91 | blkpr(FILE *fp, Char **av) | 91 | blkpr(FILE *fp, Char **av) | |
92 | { | 92 | { | |
93 | for (; *av; av++) { | 93 | for (; *av; av++) { | |
94 | (void)fprintf(fp, "%s", vis_str(*av)); | 94 | (void)fprintf(fp, "%s", vis_str(*av)); | |
95 | if (av[1]) | 95 | if (av[1]) | |
96 | (void)fprintf(fp, " "); | 96 | (void)fprintf(fp, " "); | |
97 | } | 97 | } | |
98 | } | 98 | } | |
99 | 99 | |||
100 | int | 100 | int | |
101 | blklen(Char **av) | 101 | blklen(Char **av) | |
102 | { | 102 | { | |
103 | int i; | 103 | int i; | |
104 | 104 | |||
105 | i = 0; | 105 | i = 0; | |
106 | while (*av++) | 106 | while (*av++) | |
107 | i++; | 107 | i++; | |
108 | return (i); | 108 | return (i); | |
109 | } | 109 | } | |
110 | 110 | |||
111 | Char ** | 111 | Char ** | |
112 | blkcpy(Char **oav, Char **bv) | 112 | blkcpy(Char **oav, Char **bv) | |
113 | { | 113 | { | |
114 | Char **av; | 114 | Char **av; | |
115 | 115 | |||
116 | av = oav; | 116 | av = oav; | |
117 | while ((*av++ = *bv++) != NULL) | 117 | while ((*av++ = *bv++) != NULL) | |
118 | continue; | 118 | continue; | |
119 | return (oav); | 119 | return (oav); | |
120 | } | 120 | } | |
121 | 121 | |||
122 | Char ** | 122 | Char ** | |
123 | blkcat(Char **up, Char **vp) | 123 | blkcat(Char **up, Char **vp) | |
124 | { | 124 | { | |
125 | (void)blkcpy(blkend(up), vp); | 125 | (void)blkcpy(blkend(up), vp); | |
126 | return (up); | 126 | return (up); | |
127 | } | 127 | } | |
128 | 128 | |||
129 | void | 129 | void | |
130 | blkfree(Char **av0) | 130 | blkfree(Char **av0) | |
131 | { | 131 | { | |
132 | Char **av; | 132 | Char **av; | |
133 | 133 | |||
134 | av = av0; | 134 | av = av0; | |
135 | if (!av0) | 135 | if (!av0) | |
136 | return; | 136 | return; | |
137 | for (; *av; av++) | 137 | for (; *av; av++) | |
138 | free(* av); | 138 | free(* av); | |
139 | free(av0); | 139 | free(av0); | |
140 | } | 140 | } | |
141 | 141 | |||
142 | Char ** | 142 | Char ** | |
143 | saveblk(Char **v) | 143 | saveblk(Char **v) | |
144 | { | 144 | { | |
145 | Char **newv, **onewv; | 145 | Char **newv, **onewv; | |
146 | 146 | |||
147 | if (v == NULL) | 147 | if (v == NULL) | |
148 | return NULL; | 148 | return NULL; | |
149 | 149 | |||
150 | newv = xcalloc((size_t)(blklen(v) + 1), sizeof(*newv)); | 150 | newv = xcalloc((size_t)(blklen(v) + 1), sizeof(*newv)); | |
151 | onewv = newv; | 151 | onewv = newv; | |
152 | while (*v) | 152 | while (*v) | |
153 | *newv++ = Strsave(*v++); | 153 | *newv++ = Strsave(*v++); | |
154 | return (onewv); | 154 | return (onewv); | |
155 | } | 155 | } | |
156 | 156 | |||
157 | #ifdef NOTUSED | 157 | #ifdef NOTUSED | |
158 | char * | 158 | char * | |
159 | strstr(char *s, char *t) | 159 | strstr(char *s, char *t) | |
160 | { | 160 | { | |
161 | do { | 161 | do { | |
162 | char *ss; | 162 | char *ss; | |
163 | char *tt; | 163 | char *tt; | |
164 | 164 | |||
165 | ss = s; | 165 | ss = s; | |
166 | tt = t; | 166 | tt = t; | |
167 | 167 | |||
168 | do | 168 | do | |
169 | if (*tt == '\0') | 169 | if (*tt == '\0') | |
170 | return (s); | 170 | return (s); | |
171 | while (*ss++ == *tt++); | 171 | while (*ss++ == *tt++); | |
172 | } while (*s++ != '\0'); | 172 | } while (*s++ != '\0'); | |
173 | return (NULL); | 173 | return (NULL); | |
174 | } | 174 | } | |
175 | 175 | |||
176 | #endif /* NOTUSED */ | 176 | #endif /* NOTUSED */ | |
177 | 177 | |||
178 | #ifndef SHORT_STRINGS | 178 | #ifndef SHORT_STRINGS | |
179 | char * | 179 | char * | |
180 | strspl(char *cp, char *dp) | 180 | strspl(char *cp, char *dp) | |
181 | { | 181 | { | |
182 | char *ep, *p, *q; | 182 | char *ep, *p, *q; | |
183 | 183 | |||
184 | if (!cp) | 184 | if (!cp) | |
185 | cp = ""; | 185 | cp = ""; | |
186 | if (!dp) | 186 | if (!dp) | |
187 | dp = ""; | 187 | dp = ""; | |
188 | for (p = cp; *p++;) | 188 | for (p = cp; *p++;) | |
189 | continue; | 189 | continue; | |
190 | for (q = dp; *q++;) | 190 | for (q = dp; *q++;) | |
191 | continue; | 191 | continue; | |
192 | ep = xmalloc((size_t)(((p - cp) + (q - dp) - 1) * sizeof(*ep))); | 192 | ep = xreallocarray(NULL, (size_t)(((p - cp) + (q - dp) - 1), sizeof(*ep))); | |
193 | for (p = ep, q = cp; *p++ = *q++;) | 193 | for (p = ep, q = cp; *p++ = *q++;) | |
194 | continue; | 194 | continue; | |
195 | for (p--, q = dp; *p++ = *q++;) | 195 | for (p--, q = dp; *p++ = *q++;) | |
196 | continue; | 196 | continue; | |
197 | return (ep); | 197 | return (ep); | |
198 | } | 198 | } | |
199 | 199 | |||
200 | #endif | 200 | #endif | |
201 | 201 | |||
202 | Char ** | 202 | Char ** | |
203 | blkspl(Char **up, Char **vp) | 203 | blkspl(Char **up, Char **vp) | |
204 | { | 204 | { | |
205 | Char **wp; | 205 | Char **wp; | |
206 | 206 | |||
207 | wp = xcalloc((size_t)(blklen(up) + blklen(vp) + 1), sizeof(*wp)); | 207 | wp = xcalloc((size_t)(blklen(up) + blklen(vp) + 1), sizeof(*wp)); | |
208 | (void)blkcpy(wp, up); | 208 | (void)blkcpy(wp, up); | |
209 | return (blkcat(wp, vp)); | 209 | return (blkcat(wp, vp)); | |
210 | } | 210 | } | |
211 | 211 | |||
212 | Char | 212 | Char | |
213 | lastchr(Char *cp) | 213 | lastchr(Char *cp) | |
214 | { | 214 | { | |
215 | if (!cp) | 215 | if (!cp) | |
216 | return (0); | 216 | return (0); | |
217 | if (!*cp) | 217 | if (!*cp) | |
218 | return (0); | 218 | return (0); | |
219 | while (cp[1]) | 219 | while (cp[1]) | |
220 | cp++; | 220 | cp++; | |
221 | return (*cp); | 221 | return (*cp); | |
222 | } | 222 | } | |
223 | 223 | |||
224 | /* | 224 | /* | |
225 | * This routine is called after an error to close up | 225 | * This routine is called after an error to close up | |
226 | * any units which may have been left open accidentally. | 226 | * any units which may have been left open accidentally. | |
227 | */ | 227 | */ | |
228 | void | 228 | void | |
229 | closem(void) | 229 | closem(void) | |
230 | { | 230 | { | |
231 | int f; | 231 | int f; | |
232 | int nofile; | 232 | int nofile; | |
233 | 233 | |||
234 | #ifdef F_CLOSEM | 234 | #ifdef F_CLOSEM | |
235 | nofile = FOLDSTD + 1; | 235 | nofile = FOLDSTD + 1; | |
236 | if (fcntl(nofile, F_CLOSEM, 0) == -1) | 236 | if (fcntl(nofile, F_CLOSEM, 0) == -1) | |
237 | #endif | 237 | #endif | |
238 | nofile = NOFILE; | 238 | nofile = NOFILE; | |
239 | 239 | |||
240 | for (f = 0; f < nofile; f++) | 240 | for (f = 0; f < nofile; f++) | |
241 | if (f != SHIN && f != SHOUT && f != SHERR && f != OLDSTD && | 241 | if (f != SHIN && f != SHOUT && f != SHERR && f != OLDSTD && | |
242 | f != FSHTTY) | 242 | f != FSHTTY) | |
243 | (void) close(f); | 243 | (void) close(f); | |
244 | } | 244 | } | |
245 | 245 | |||
246 | void | 246 | void | |
247 | donefds(void) | 247 | donefds(void) | |
248 | { | 248 | { | |
249 | (void)close(0); | 249 | (void)close(0); | |
250 | (void)close(1); | 250 | (void)close(1); | |
251 | (void)close(2); | 251 | (void)close(2); | |
252 | 252 | |||
253 | didfds = 0; | 253 | didfds = 0; | |
254 | } | 254 | } | |
255 | 255 | |||
256 | /* | 256 | /* | |
257 | * Move descriptor i to j. | 257 | * Move descriptor i to j. | |
258 | * If j is -1 then we just want to get i to a safe place, | 258 | * If j is -1 then we just want to get i to a safe place, | |
259 | * i.e. to a unit > 2. This also happens in dcopy. | 259 | * i.e. to a unit > 2. This also happens in dcopy. | |
260 | */ | 260 | */ | |
261 | int | 261 | int | |
262 | dmove(int i, int j) | 262 | dmove(int i, int j) | |
263 | { | 263 | { | |
264 | if (i == j || i < 0) | 264 | if (i == j || i < 0) | |
265 | return (i); | 265 | return (i); | |
266 | if (j >= 0) { | 266 | if (j >= 0) { | |
267 | (void)dup2(i, j); | 267 | (void)dup2(i, j); | |
268 | if (j != i) | 268 | if (j != i) | |
269 | (void)close(i); | 269 | (void)close(i); | |
270 | return (j); | 270 | return (j); | |
271 | } | 271 | } | |
272 | j = dcopy(i, j); | 272 | j = dcopy(i, j); | |
273 | if (j != i) | 273 | if (j != i) | |
274 | (void)close(i); | 274 | (void)close(i); | |
275 | return (j); | 275 | return (j); | |
276 | } | 276 | } | |
277 | 277 | |||
278 | int | 278 | int | |
279 | dcopy(int i, int j) | 279 | dcopy(int i, int j) | |
280 | { | 280 | { | |
281 | if (i == j || i < 0 || (j < 0 && i > 2)) | 281 | if (i == j || i < 0 || (j < 0 && i > 2)) | |
282 | return (i); | 282 | return (i); | |
283 | if (j >= 0) { | 283 | if (j >= 0) { | |
284 | (void)dup2(i, j); | 284 | (void)dup2(i, j); | |
285 | return (j); | 285 | return (j); | |
286 | } | 286 | } | |
287 | return (renum(i, j)); | 287 | return (renum(i, j)); | |
288 | } | 288 | } | |
289 | 289 | |||
290 | static int | 290 | static int | |
291 | renum(int i, int j) | 291 | renum(int i, int j) | |
292 | { | 292 | { | |
293 | int k; | 293 | int k; | |
294 | 294 | |||
295 | k = dup(i); | 295 | k = dup(i); | |
296 | if (k < 0) | 296 | if (k < 0) | |
297 | return (-1); | 297 | return (-1); | |
298 | if (j == -1 && k > 2) | 298 | if (j == -1 && k > 2) | |
299 | return (k); | 299 | return (k); | |
300 | if (k != j) { | 300 | if (k != j) { | |
301 | j = renum(k, j); | 301 | j = renum(k, j); | |
302 | (void)close(k); | 302 | (void)close(k); | |
303 | return (j); | 303 | return (j); | |
304 | } | 304 | } | |
305 | return (k); | 305 | return (k); | |
306 | } | 306 | } | |
307 | 307 | |||
308 | /* | 308 | /* | |
309 | * Left shift a command argument list, discarding | 309 | * Left shift a command argument list, discarding | |
310 | * the first c arguments. Used in "shift" commands | 310 | * the first c arguments. Used in "shift" commands | |
311 | * as well as by commands like "repeat". | 311 | * as well as by commands like "repeat". | |
312 | */ | 312 | */ | |
313 | void | 313 | void | |
314 | lshift(Char **v, size_t c) | 314 | lshift(Char **v, size_t c) | |
315 | { | 315 | { | |
316 | Char **u; | 316 | Char **u; | |
317 | 317 | |||
318 | for (u = v; *u && c-- > 0; u++) | 318 | for (u = v; *u && c-- > 0; u++) | |
319 | free(*u); | 319 | free(*u); | |
320 | (void)blkcpy(v, u); | 320 | (void)blkcpy(v, u); | |
321 | } | 321 | } | |
322 | 322 | |||
323 | int | 323 | int | |
324 | number(Char *cp) | 324 | number(Char *cp) | |
325 | { | 325 | { | |
326 | if (!cp) | 326 | if (!cp) | |
327 | return(0); | 327 | return(0); | |
328 | if (*cp == '-') { | 328 | if (*cp == '-') { | |
329 | cp++; | 329 | cp++; | |
330 | if (!Isdigit(*cp)) | 330 | if (!Isdigit(*cp)) | |
331 | return (0); | 331 | return (0); | |
332 | cp++; | 332 | cp++; | |
333 | } | 333 | } | |
334 | while (*cp && Isdigit(*cp)) | 334 | while (*cp && Isdigit(*cp)) | |
335 | cp++; | 335 | cp++; | |
336 | return (*cp == 0); | 336 | return (*cp == 0); | |
337 | } | 337 | } | |
338 | 338 | |||
339 | Char ** | 339 | Char ** | |
340 | copyblk(Char **v) | 340 | copyblk(Char **v) | |
341 | { | 341 | { | |
342 | Char **nv; | 342 | Char **nv; | |
343 | 343 | |||
344 | nv = xcalloc((size_t)(blklen(v) + 1), sizeof(*nv)); | 344 | nv = xcalloc((size_t)(blklen(v) + 1), sizeof(*nv)); | |
345 | 345 | |||
346 | return (blkcpy(nv, v)); | 346 | return (blkcpy(nv, v)); | |
347 | } | 347 | } | |
348 | 348 | |||
349 | #ifndef SHORT_STRINGS | 349 | #ifndef SHORT_STRINGS | |
350 | char * | 350 | char * | |
351 | strend(char *cp) | 351 | strend(char *cp) | |
352 | { | 352 | { | |
353 | if (!cp) | 353 | if (!cp) | |
354 | return (cp); | 354 | return (cp); | |
355 | while (*cp) | 355 | while (*cp) | |
356 | cp++; | 356 | cp++; | |
357 | return (cp); | 357 | return (cp); | |
358 | } | 358 | } | |
359 | 359 | |||
360 | #endif /* SHORT_STRINGS */ | 360 | #endif /* SHORT_STRINGS */ | |
361 | 361 | |||
362 | Char * | 362 | Char * | |
363 | strip(Char *cp) | 363 | strip(Char *cp) | |
364 | { | 364 | { | |
365 | Char *dp; | 365 | Char *dp; | |
366 | 366 | |||
367 | dp = cp; | 367 | dp = cp; | |
368 | if (!cp) | 368 | if (!cp) | |
369 | return (cp); | 369 | return (cp); | |
370 | while ((*dp++ &= TRIM) != '\0') | 370 | while ((*dp++ &= TRIM) != '\0') | |
371 | continue; | 371 | continue; | |
372 | return (cp); | 372 | return (cp); | |
373 | } | 373 | } | |
374 | 374 | |||
375 | Char * | 375 | Char * | |
376 | quote(Char *cp) | 376 | quote(Char *cp) | |
377 | { | 377 | { | |
378 | Char *dp; | 378 | Char *dp; | |
379 | 379 | |||
380 | dp = cp; | 380 | dp = cp; | |
381 | if (!cp) | 381 | if (!cp) | |
382 | return (cp); | 382 | return (cp); | |
383 | while (*dp != '\0') | 383 | while (*dp != '\0') | |
384 | *dp++ |= QUOTE; | 384 | *dp++ |= QUOTE; | |
385 | return (cp); | 385 | return (cp); | |
386 | } | 386 | } | |
387 | 387 | |||
388 | void | 388 | void | |
389 | udvar(Char *name) | 389 | udvar(Char *name) | |
390 | { | 390 | { | |
391 | setname(vis_str(name)); | 391 | setname(vis_str(name)); | |
392 | stderror(ERR_NAME | ERR_UNDVAR); | 392 | stderror(ERR_NAME | ERR_UNDVAR); | |
393 | /* NOTREACHED */ | 393 | /* NOTREACHED */ | |
394 | } | 394 | } | |
395 | 395 | |||
396 | int | 396 | int | |
397 | prefix(Char *sub, Char *str) | 397 | prefix(Char *sub, Char *str) | |
398 | { | 398 | { | |
399 | for (;;) { | 399 | for (;;) { | |
400 | if (*sub == 0) | 400 | if (*sub == 0) | |
401 | return (1); | 401 | return (1); | |
402 | if (*str == 0) | 402 | if (*str == 0) | |
403 | return (0); | 403 | return (0); | |
404 | if (*sub++ != *str++) | 404 | if (*sub++ != *str++) | |
405 | return (0); | 405 | return (0); | |
406 | } | 406 | } | |
407 | } | 407 | } |
--- src/bin/csh/str.c 2019/01/05 16:54:00 1.16
+++ src/bin/csh/str.c 2024/04/24 15:49:03 1.17
@@ -1,437 +1,437 @@ | @@ -1,437 +1,437 @@ | |||
1 | /* $NetBSD: str.c,v 1.16 2019/01/05 16:54:00 christos Exp $ */ | 1 | /* $NetBSD: str.c,v 1.17 2024/04/24 15:49:03 nia Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1991, 1993 | 4 | * Copyright (c) 1991, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the University nor the names of its contributors | 15 | * 3. Neither the name of the University nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | #if 0 | 34 | #if 0 | |
35 | static char sccsid[] = "@(#)str.c 8.1 (Berkeley) 5/31/93"; | 35 | static char sccsid[] = "@(#)str.c 8.1 (Berkeley) 5/31/93"; | |
36 | #else | 36 | #else | |
37 | __RCSID("$NetBSD: str.c,v 1.16 2019/01/05 16:54:00 christos Exp $"); | 37 | __RCSID("$NetBSD: str.c,v 1.17 2024/04/24 15:49:03 nia Exp $"); | |
38 | #endif | 38 | #endif | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #define MALLOC_INCR 128 | 41 | #define MALLOC_INCR 128 | |
42 | 42 | |||
43 | /* | 43 | /* | |
44 | * tc.str.c: Short string package | 44 | * tc.str.c: Short string package | |
45 | * This has been a lesson of how to write buggy code! | 45 | * This has been a lesson of how to write buggy code! | |
46 | */ | 46 | */ | |
47 | 47 | |||
48 | #include <sys/types.h> | 48 | #include <sys/types.h> | |
49 | 49 | |||
50 | #include <stdarg.h> | 50 | #include <stdarg.h> | |
51 | #include <vis.h> | 51 | #include <vis.h> | |
52 | 52 | |||
53 | #include "csh.h" | 53 | #include "csh.h" | |
54 | #include "extern.h" | 54 | #include "extern.h" | |
55 | 55 | |||
56 | #ifdef SHORT_STRINGS | 56 | #ifdef SHORT_STRINGS | |
57 | 57 | |||
58 | Char ** | 58 | Char ** | |
59 | blk2short(char **src) | 59 | blk2short(char **src) | |
60 | { | 60 | { | |
61 | Char **dst, **sdst; | 61 | Char **dst, **sdst; | |
62 | size_t n; | 62 | size_t n; | |
63 | 63 | |||
64 | /* | 64 | /* | |
65 | * Count | 65 | * Count | |
66 | */ | 66 | */ | |
67 | for (n = 0; src[n] != NULL; n++) | 67 | for (n = 0; src[n] != NULL; n++) | |
68 | continue; | 68 | continue; | |
69 | sdst = dst = xmalloc((size_t)((n + 1) * sizeof(*dst))); | 69 | sdst = dst = xreallocarray(NULL, n + 1, sizeof(*dst)); | |
70 | 70 | |||
71 | for (; *src != NULL; src++) | 71 | for (; *src != NULL; src++) | |
72 | *dst++ = SAVE(*src); | 72 | *dst++ = SAVE(*src); | |
73 | *dst = NULL; | 73 | *dst = NULL; | |
74 | return (sdst); | 74 | return (sdst); | |
75 | } | 75 | } | |
76 | 76 | |||
77 | char ** | 77 | char ** | |
78 | short2blk(Char *const *src) | 78 | short2blk(Char *const *src) | |
79 | { | 79 | { | |
80 | char **dst, **sdst; | 80 | char **dst, **sdst; | |
81 | size_t n; | 81 | size_t n; | |
82 | 82 | |||
83 | /* | 83 | /* | |
84 | * Count | 84 | * Count | |
85 | */ | 85 | */ | |
86 | for (n = 0; src[n] != NULL; n++) | 86 | for (n = 0; src[n] != NULL; n++) | |
87 | continue; | 87 | continue; | |
88 | sdst = dst = xmalloc((size_t)((n + 1) * sizeof(*dst))); | 88 | sdst = dst = xreallocarray(NULL, n + 1, sizeof(*dst)); | |
89 | 89 | |||
90 | for (; *src != NULL; src++) | 90 | for (; *src != NULL; src++) | |
91 | *dst++ = strsave(short2str(*src)); | 91 | *dst++ = strsave(short2str(*src)); | |
92 | *dst = NULL; | 92 | *dst = NULL; | |
93 | return (sdst); | 93 | return (sdst); | |
94 | } | 94 | } | |
95 | 95 | |||
96 | Char * | 96 | Char * | |
97 | str2short(const char *src) | 97 | str2short(const char *src) | |
98 | { | 98 | { | |
99 | static Char *sdst; | 99 | static Char *sdst; | |
100 | Char *dst, *edst; | 100 | Char *dst, *edst; | |
101 | static size_t dstsize = 0; | 101 | static size_t dstsize = 0; | |
102 | 102 | |||
103 | if (src == NULL) | 103 | if (src == NULL) | |
104 | return (NULL); | 104 | return (NULL); | |
105 | 105 | |||
106 | if (sdst == (NULL)) { | 106 | if (sdst == (NULL)) { | |
107 | dstsize = MALLOC_INCR; | 107 | dstsize = MALLOC_INCR; | |
108 | sdst = xmalloc((size_t)dstsize * sizeof(*sdst)); | 108 | sdst = xreallocarray(NULL, (size_t)dstsize, sizeof(*sdst)); | |
109 | } | 109 | } | |
110 | 110 | |||
111 | dst = sdst; | 111 | dst = sdst; | |
112 | edst = &dst[dstsize]; | 112 | edst = &dst[dstsize]; | |
113 | while (*src) { | 113 | while (*src) { | |
114 | *dst++ = (Char) ((unsigned char) *src++); | 114 | *dst++ = (Char) ((unsigned char) *src++); | |
115 | if (dst == edst) { | 115 | if (dst == edst) { | |
116 | dstsize += MALLOC_INCR; | 116 | dstsize += MALLOC_INCR; | |
117 | sdst = xrealloc(sdst, (size_t)dstsize * sizeof(*sdst)); | 117 | sdst = xreallocarray(sdst, (size_t)dstsize, sizeof(*sdst)); | |
118 | edst = &sdst[dstsize]; | 118 | edst = &sdst[dstsize]; | |
119 | dst = &edst[-MALLOC_INCR]; | 119 | dst = &edst[-MALLOC_INCR]; | |
120 | } | 120 | } | |
121 | } | 121 | } | |
122 | *dst = 0; | 122 | *dst = 0; | |
123 | return (sdst); | 123 | return (sdst); | |
124 | } | 124 | } | |
125 | 125 | |||
126 | char * | 126 | char * | |
127 | short2str(const Char *src) | 127 | short2str(const Char *src) | |
128 | { | 128 | { | |
129 | static char *sdst = NULL; | 129 | static char *sdst = NULL; | |
130 | static size_t dstsize = 0; | 130 | static size_t dstsize = 0; | |
131 | char *dst, *edst; | 131 | char *dst, *edst; | |
132 | 132 | |||
133 | if (src == NULL) | 133 | if (src == NULL) | |
134 | return (NULL); | 134 | return (NULL); | |
135 | 135 | |||
136 | if (sdst == NULL) { | 136 | if (sdst == NULL) { | |
137 | dstsize = MALLOC_INCR; | 137 | dstsize = MALLOC_INCR; | |
138 | sdst = xmalloc((size_t)dstsize * sizeof(*sdst)); | 138 | sdst = xreallocarray(NULL, dstsize, sizeof(*sdst)); | |
139 | } | 139 | } | |
140 | dst = sdst; | 140 | dst = sdst; | |
141 | edst = &dst[dstsize]; | 141 | edst = &dst[dstsize]; | |
142 | while (*src) { | 142 | while (*src) { | |
143 | *dst++ = (char) *src++; | 143 | *dst++ = (char) *src++; | |
144 | if (dst == edst) { | 144 | if (dst == edst) { | |
145 | dstsize += MALLOC_INCR; | 145 | dstsize += MALLOC_INCR; | |
146 | sdst = xrealloc(sdst, (size_t)dstsize * sizeof(*sdst)); | 146 | sdst = xreallocarray(sdst, dstsize, sizeof(*sdst)); | |
147 | edst = &sdst[dstsize]; | 147 | edst = &sdst[dstsize]; | |
148 | dst = &edst[-MALLOC_INCR]; | 148 | dst = &edst[-MALLOC_INCR]; | |
149 | } | 149 | } | |
150 | } | 150 | } | |
151 | *dst = 0; | 151 | *dst = 0; | |
152 | return (sdst); | 152 | return (sdst); | |
153 | } | 153 | } | |
154 | 154 | |||
155 | Char * | 155 | Char * | |
156 | s_strcpy(Char *dst, const Char *src) | 156 | s_strcpy(Char *dst, const Char *src) | |
157 | { | 157 | { | |
158 | Char *sdst; | 158 | Char *sdst; | |
159 | 159 | |||
160 | sdst = dst; | 160 | sdst = dst; | |
161 | while ((*dst++ = *src++) != '\0') | 161 | while ((*dst++ = *src++) != '\0') | |
162 | continue; | 162 | continue; | |
163 | return (sdst); | 163 | return (sdst); | |
164 | } | 164 | } | |
165 | 165 | |||
166 | Char * | 166 | Char * | |
167 | s_strncpy(Char *dst, const Char *src, size_t n) | 167 | s_strncpy(Char *dst, const Char *src, size_t n) | |
168 | { | 168 | { | |
169 | Char *sdst; | 169 | Char *sdst; | |
170 | 170 | |||
171 | if (n == 0) | 171 | if (n == 0) | |
172 | return(dst); | 172 | return(dst); | |
173 | 173 | |||
174 | sdst = dst; | 174 | sdst = dst; | |
175 | do | 175 | do | |
176 | if ((*dst++ = *src++) == '\0') { | 176 | if ((*dst++ = *src++) == '\0') { | |
177 | while (--n != 0) | 177 | while (--n != 0) | |
178 | *dst++ = '\0'; | 178 | *dst++ = '\0'; | |
179 | return(sdst); | 179 | return(sdst); | |
180 | } | 180 | } | |
181 | while (--n != 0); | 181 | while (--n != 0); | |
182 | return (sdst); | 182 | return (sdst); | |
183 | } | 183 | } | |
184 | 184 | |||
185 | Char * | 185 | Char * | |
186 | s_strcat(Char *dst, const Char *src) | 186 | s_strcat(Char *dst, const Char *src) | |
187 | { | 187 | { | |
188 | short *sdst; | 188 | short *sdst; | |
189 | 189 | |||
190 | sdst = dst; | 190 | sdst = dst; | |
191 | while (*dst++) | 191 | while (*dst++) | |
192 | continue; | 192 | continue; | |
193 | --dst; | 193 | --dst; | |
194 | while ((*dst++ = *src++) != '\0') | 194 | while ((*dst++ = *src++) != '\0') | |
195 | continue; | 195 | continue; | |
196 | return (sdst); | 196 | return (sdst); | |
197 | } | 197 | } | |
198 | 198 | |||
199 | #ifdef NOTUSED | 199 | #ifdef NOTUSED | |
200 | Char * | 200 | Char * | |
201 | s_strncat(Char *dst, Char *src, size_t n) | 201 | s_strncat(Char *dst, Char *src, size_t n) | |
202 | { | 202 | { | |
203 | Char *sdst; | 203 | Char *sdst; | |
204 | 204 | |||
205 | if (n == 0) | 205 | if (n == 0) | |
206 | return (dst); | 206 | return (dst); | |
207 | 207 | |||
208 | sdst = dst; | 208 | sdst = dst; | |
209 | 209 | |||
210 | while (*dst++) | 210 | while (*dst++) | |
211 | continue; | 211 | continue; | |
212 | --dst; | 212 | --dst; | |
213 | 213 | |||
214 | do | 214 | do | |
215 | if ((*dst++ = *src++) == '\0') | 215 | if ((*dst++ = *src++) == '\0') | |
216 | return(sdst); | 216 | return(sdst); | |
217 | while (--n != 0) | 217 | while (--n != 0) | |
218 | continue; | 218 | continue; | |
219 | 219 | |||
220 | *dst = '\0'; | 220 | *dst = '\0'; | |
221 | return (sdst); | 221 | return (sdst); | |
222 | } | 222 | } | |
223 | 223 | |||
224 | #endif | 224 | #endif | |
225 | 225 | |||
226 | Char * | 226 | Char * | |
227 | s_strchr(const Char *str, int ch) | 227 | s_strchr(const Char *str, int ch) | |
228 | { | 228 | { | |
229 | do | 229 | do | |
230 | if (*str == ch) | 230 | if (*str == ch) | |
231 | return __UNCONST(str); | 231 | return __UNCONST(str); | |
232 | while (*str++); | 232 | while (*str++); | |
233 | return (NULL); | 233 | return (NULL); | |
234 | } | 234 | } | |
235 | 235 | |||
236 | Char * | 236 | Char * | |
237 | s_strrchr(const Char *str, int ch) | 237 | s_strrchr(const Char *str, int ch) | |
238 | { | 238 | { | |
239 | const Char *rstr; | 239 | const Char *rstr; | |
240 | 240 | |||
241 | rstr = NULL; | 241 | rstr = NULL; | |
242 | do | 242 | do | |
243 | if (*str == ch) | 243 | if (*str == ch) | |
244 | rstr = str; | 244 | rstr = str; | |
245 | while (*str++); | 245 | while (*str++); | |
246 | return __UNCONST(rstr); | 246 | return __UNCONST(rstr); | |
247 | } | 247 | } | |
248 | 248 | |||
249 | size_t | 249 | size_t | |
250 | s_strlen(const Char *str) | 250 | s_strlen(const Char *str) | |
251 | { | 251 | { | |
252 | size_t n; | 252 | size_t n; | |
253 | 253 | |||
254 | for (n = 0; *str++; n++) | 254 | for (n = 0; *str++; n++) | |
255 | continue; | 255 | continue; | |
256 | return (n); | 256 | return (n); | |
257 | } | 257 | } | |
258 | 258 | |||
259 | int | 259 | int | |
260 | s_strcmp(const Char *str1, const Char *str2) | 260 | s_strcmp(const Char *str1, const Char *str2) | |
261 | { | 261 | { | |
262 | for (; *str1 && *str1 == *str2; str1++, str2++) | 262 | for (; *str1 && *str1 == *str2; str1++, str2++) | |
263 | continue; | 263 | continue; | |
264 | /* | 264 | /* | |
265 | * The following case analysis is necessary so that characters which look | 265 | * The following case analysis is necessary so that characters which look | |
266 | * negative collate low against normal characters but high against the | 266 | * negative collate low against normal characters but high against the | |
267 | * end-of-string NUL. | 267 | * end-of-string NUL. | |
268 | */ | 268 | */ | |
269 | if (*str1 == '\0' && *str2 == '\0') | 269 | if (*str1 == '\0' && *str2 == '\0') | |
270 | return (0); | 270 | return (0); | |
271 | else if (*str1 == '\0') | 271 | else if (*str1 == '\0') | |
272 | return (-1); | 272 | return (-1); | |
273 | else if (*str2 == '\0') | 273 | else if (*str2 == '\0') | |
274 | return (1); | 274 | return (1); | |
275 | else | 275 | else | |
276 | return (*str1 - *str2); | 276 | return (*str1 - *str2); | |
277 | } | 277 | } | |
278 | 278 | |||
279 | int | 279 | int | |
280 | s_strncmp(const Char *str1, const Char *str2, size_t n) | 280 | s_strncmp(const Char *str1, const Char *str2, size_t n) | |
281 | { | 281 | { | |
282 | if (n == 0) | 282 | if (n == 0) | |
283 | return (0); | 283 | return (0); | |
284 | do { | 284 | do { | |
285 | if (*str1 != *str2) { | 285 | if (*str1 != *str2) { | |
286 | /* | 286 | /* | |
287 | * The following case analysis is necessary so that characters | 287 | * The following case analysis is necessary so that characters | |
288 | * which look negative collate low against normal characters | 288 | * which look negative collate low against normal characters | |
289 | * but high against the end-of-string NUL. | 289 | * but high against the end-of-string NUL. | |
290 | */ | 290 | */ | |
291 | if (*str1 == '\0') | 291 | if (*str1 == '\0') | |
292 | return (-1); | 292 | return (-1); | |
293 | else if (*str2 == '\0') | 293 | else if (*str2 == '\0') | |
294 | return (1); | 294 | return (1); | |
295 | else | 295 | else | |
296 | return (*str1 - *str2); | 296 | return (*str1 - *str2); | |
297 | } | 297 | } | |
298 | if (*str1 == '\0') | 298 | if (*str1 == '\0') | |
299 | return(0); | 299 | return(0); | |
300 | str1++, str2++; | 300 | str1++, str2++; | |
301 | } while (--n != 0); | 301 | } while (--n != 0); | |
302 | return(0); | 302 | return(0); | |
303 | } | 303 | } | |
304 | 304 | |||
305 | Char * | 305 | Char * | |
306 | s_strsave(const Char *s) | 306 | s_strsave(const Char *s) | |
307 | { | 307 | { | |
308 | const Char *p; | 308 | const Char *p; | |
309 | Char *n; | 309 | Char *n; | |
310 | 310 | |||
311 | if (s == 0) | 311 | if (s == 0) | |
312 | s = STRNULL; | 312 | s = STRNULL; | |
313 | for (p = s; *p++;) | 313 | for (p = s; *p++;) | |
314 | continue; | 314 | continue; | |
315 | p = n = xmalloc((size_t)(p - s) * sizeof(*n)); | 315 | p = n = xreallocarray(NULL, (size_t)(p - s), sizeof(*n)); | |
316 | while ((*n++ = *s++) != '\0') | 316 | while ((*n++ = *s++) != '\0') | |
317 | continue; | 317 | continue; | |
318 | return __UNCONST(p); | 318 | return __UNCONST(p); | |
319 | } | 319 | } | |
320 | 320 | |||
321 | Char * | 321 | Char * | |
322 | s_strspl(const Char *cp, const Char *dp) | 322 | s_strspl(const Char *cp, const Char *dp) | |
323 | { | 323 | { | |
324 | Char *ep, *d; | 324 | Char *ep, *d; | |
325 | const Char *p, *q; | 325 | const Char *p, *q; | |
326 | 326 | |||
327 | if (!cp) | 327 | if (!cp) | |
328 | cp = STRNULL; | 328 | cp = STRNULL; | |
329 | if (!dp) | 329 | if (!dp) | |
330 | dp = STRNULL; | 330 | dp = STRNULL; | |
331 | for (p = cp; *p++;) | 331 | for (p = cp; *p++;) | |
332 | continue; | 332 | continue; | |
333 | for (q = dp; *q++;) | 333 | for (q = dp; *q++;) | |
334 | continue; | 334 | continue; | |
335 | ep = xmalloc((size_t)((p - cp) + (q - dp) - 1) * sizeof(*ep)); | 335 | ep = xreallocarray(NULL, (size_t)((p - cp) + (q - dp) - 1), sizeof(*ep)); | |
336 | for (d = ep, q = cp; (*d++ = *q++) != '\0';) | 336 | for (d = ep, q = cp; (*d++ = *q++) != '\0';) | |
337 | continue; | 337 | continue; | |
338 | for (d--, q = dp; (*d++ = *q++) != '\0';) | 338 | for (d--, q = dp; (*d++ = *q++) != '\0';) | |
339 | continue; | 339 | continue; | |
340 | return (ep); | 340 | return (ep); | |
341 | } | 341 | } | |
342 | 342 | |||
343 | Char * | 343 | Char * | |
344 | s_strend(const Char *cp) | 344 | s_strend(const Char *cp) | |
345 | { | 345 | { | |
346 | if (!cp) | 346 | if (!cp) | |
347 | return __UNCONST(cp); | 347 | return __UNCONST(cp); | |
348 | while (*cp) | 348 | while (*cp) | |
349 | cp++; | 349 | cp++; | |
350 | return __UNCONST(cp); | 350 | return __UNCONST(cp); | |
351 | } | 351 | } | |
352 | 352 | |||
353 | Char * | 353 | Char * | |
354 | s_strstr(const Char *s, const Char *t) | 354 | s_strstr(const Char *s, const Char *t) | |
355 | { | 355 | { | |
356 | do { | 356 | do { | |
357 | const Char *ss = s; | 357 | const Char *ss = s; | |
358 | const Char *tt = t; | 358 | const Char *tt = t; | |
359 | 359 | |||
360 | do | 360 | do | |
361 | if (*tt == '\0') | 361 | if (*tt == '\0') | |
362 | return __UNCONST(s); | 362 | return __UNCONST(s); | |
363 | while (*ss++ == *tt++); | 363 | while (*ss++ == *tt++); | |
364 | } while (*s++ != '\0'); | 364 | } while (*s++ != '\0'); | |
365 | return (NULL); | 365 | return (NULL); | |
366 | } | 366 | } | |
367 | #endif /* SHORT_STRINGS */ | 367 | #endif /* SHORT_STRINGS */ | |
368 | 368 | |||
369 | char * | 369 | char * | |
370 | short2qstr(const Char *src) | 370 | short2qstr(const Char *src) | |
371 | { | 371 | { | |
372 | static char *sdst = NULL; | 372 | static char *sdst = NULL; | |
373 | static size_t dstsize = 0; | 373 | static size_t dstsize = 0; | |
374 | char *dst, *edst; | 374 | char *dst, *edst; | |
375 | 375 | |||
376 | if (src == NULL) | 376 | if (src == NULL) | |
377 | return (NULL); | 377 | return (NULL); | |
378 | 378 | |||
379 | if (sdst == NULL) { | 379 | if (sdst == NULL) { | |
380 | dstsize = MALLOC_INCR; | 380 | dstsize = MALLOC_INCR; | |
381 | sdst = xmalloc((size_t)dstsize * sizeof(*sdst)); | 381 | sdst = xreallocarray(NULL, dstsize, sizeof(*sdst)); | |
382 | } | 382 | } | |
383 | dst = sdst; | 383 | dst = sdst; | |
384 | edst = &dst[dstsize]; | 384 | edst = &dst[dstsize]; | |
385 | while (*src) { | 385 | while (*src) { | |
386 | 386 | |||
387 | if (*src & QUOTE) { | 387 | if (*src & QUOTE) { | |
388 | *dst++ = '\\'; | 388 | *dst++ = '\\'; | |
389 | if (dst == edst) { | 389 | if (dst == edst) { | |
390 | dstsize += MALLOC_INCR; | 390 | dstsize += MALLOC_INCR; | |
391 | sdst = xrealloc(sdst, (size_t)dstsize * sizeof(*sdst)); | 391 | sdst = xreallocarray(sdst, (size_t)dstsize, sizeof(*sdst)); | |
392 | edst = &sdst[dstsize]; | 392 | edst = &sdst[dstsize]; | |
393 | dst = &edst[-MALLOC_INCR]; | 393 | dst = &edst[-MALLOC_INCR]; | |
394 | } | 394 | } | |
395 | } | 395 | } | |
396 | *dst++ = (char) *src++; | 396 | *dst++ = (char) *src++; | |
397 | if (dst == edst) { | 397 | if (dst == edst) { | |
398 | dstsize += MALLOC_INCR; | 398 | dstsize += MALLOC_INCR; | |
399 | sdst = xrealloc(sdst, (size_t)dstsize * sizeof(*sdst)); | 399 | sdst = xreallocarray(sdst, (size_t)dstsize, sizeof(*sdst)); | |
400 | edst = &sdst[dstsize]; | 400 | edst = &sdst[dstsize]; | |
401 | dst = &edst[-MALLOC_INCR]; | 401 | dst = &edst[-MALLOC_INCR]; | |
402 | } | 402 | } | |
403 | } | 403 | } | |
404 | *dst = 0; | 404 | *dst = 0; | |
405 | return (sdst); | 405 | return (sdst); | |
406 | } | 406 | } | |
407 | 407 | |||
408 | /* | 408 | /* | |
409 | * XXX: Should we worry about QUOTE'd chars? | 409 | * XXX: Should we worry about QUOTE'd chars? | |
410 | */ | 410 | */ | |
411 | char * | 411 | char * | |
412 | vis_str(const Char *cp) | 412 | vis_str(const Char *cp) | |
413 | { | 413 | { | |
414 | static char *sdst = NULL; | 414 | static char *sdst = NULL; | |
415 | static size_t dstsize = 0; | 415 | static size_t dstsize = 0; | |
416 | const Char *dp; | 416 | const Char *dp; | |
417 | size_t n; | 417 | size_t n; | |
418 | 418 | |||
419 | if (cp == NULL) | 419 | if (cp == NULL) | |
420 | return (NULL); | 420 | return (NULL); | |
421 | 421 | |||
422 | for (dp = cp; *dp++;) | 422 | for (dp = cp; *dp++;) | |
423 | continue; | 423 | continue; | |
424 | n = ((size_t)(dp - cp) << 2) + 1; /* 4 times + NULL */ | 424 | n = ((size_t)(dp - cp) << 2) + 1; /* 4 times + NULL */ | |
425 | if (dstsize < n) { | 425 | if (dstsize < n) { | |
426 | sdst = (dstsize ? | 426 | sdst = (dstsize ? | |
427 | xrealloc(sdst, (size_t)n * sizeof(*sdst)) : | 427 | xreallocarray(sdst, (size_t)n, sizeof(*sdst)) : | |
428 | xmalloc((size_t)n * sizeof(*sdst))); | 428 | xreallocarray(NULL, (size_t)n, sizeof(*sdst))); | |
429 | dstsize = n; | 429 | dstsize = n; | |
430 | } | 430 | } | |
431 | /* | 431 | /* | |
432 | * XXX: When we are in AsciiOnly we want all characters >= 0200 to | 432 | * XXX: When we are in AsciiOnly we want all characters >= 0200 to | |
433 | * be encoded, but currently there is no way in vis to do that. | 433 | * be encoded, but currently there is no way in vis to do that. | |
434 | */ | 434 | */ | |
435 | (void)strvis(sdst, short2str(cp), VIS_NOSLASH); | 435 | (void)strvis(sdst, short2str(cp), VIS_NOSLASH); | |
436 | return (sdst); | 436 | return (sdst); | |
437 | } | 437 | } |