Wed Apr 24 15:49:03 2024 UTC (40d)
csh: replace malloc(x * y) and realloc(x * y) with reallocarray


(nia)
diff -r1.35 -r1.36 src/bin/csh/dir.c
diff -r1.33 -r1.34 src/bin/csh/file.c
diff -r1.44 -r1.45 src/bin/csh/func.c
diff -r1.31 -r1.32 src/bin/csh/glob.c
diff -r1.22 -r1.23 src/bin/csh/misc.c
diff -r1.16 -r1.17 src/bin/csh/str.c

cvs diff -r1.35 -r1.36 src/bin/csh/dir.c (switch to unified diff)

--- 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
35static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 5/31/93"; 35static 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
56static struct directory *dfind(Char *); 56static struct directory *dfind(Char *);
57static Char *dfollow(Char *); 57static Char *dfollow(Char *);
58static void printdirs(void); 58static void printdirs(void);
59static Char *dgoto(Char *); 59static Char *dgoto(Char *);
60static void skipargs(Char ***, const char *); 60static void skipargs(Char ***, const char *);
61static void dnewcwd(struct directory *); 61static void dnewcwd(struct directory *);
62static void dset(Char *); 62static void dset(Char *);
63 63
64struct directory dhead; /* "head" of loop */ 64struct directory dhead; /* "head" of loop */
65int printd; /* force name to be printed */ 65int printd; /* force name to be printed */
66 66
67static int dirflag = 0; 67static int dirflag = 0;
68 68
69struct directory *dcwd; 69struct directory *dcwd;
70 70
71/* 71/*
72 * dinit - initialize current working directory 72 * dinit - initialize current working directory
73 */ 73 */
74void 74void
75dinit(Char *hp) 75dinit(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
140static void 140static void
141dset(Char *dp) 141dset(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
161static void 161static void
162skipargs(Char ***v, const char *str) 162skipargs(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 */
190void 190void
191/*ARGSUSED*/ 191/*ARGSUSED*/
192dodirs(Char **v, struct command *t) 192dodirs(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
201static void 201static void
202printdirs(void) 202printdirs(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
240void 240void
241dtildepr(Char *home, Char *dir) 241dtildepr(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
249void 249void
250dtilde(void) 250dtilde(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 */
269Char * 269Char *
270dnormalize(Char *cp) 270dnormalize(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 */
334void 334void
335/*ARGSUSED*/ 335/*ARGSUSED*/
336dochngd(Char **v, struct command *t) 336dochngd(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
377static Char * 377static Char *
378dgoto(Char *cp) 378dgoto(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 */
415static Char * 416static Char *
416dfollow(Char *cp) 417dfollow(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 */
477void 478void
478/*ARGSUSED*/ 479/*ARGSUSED*/
479dopushd(Char **v, struct command *t) 480dopushd(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 */
527static struct directory * 528static struct directory *
528dfind(Char *cp) 529dfind(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 */
556void 557void
557/*ARGSUSED*/ 558/*ARGSUSED*/
558dopopd(Char **v, struct command *t) 559dopopd(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 */
593void 594void
594dfree(struct directory *dp) 595dfree(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 */
611Char * 612Char *
612dcanon(Char *cp, Char *p) 613dcanon(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 */
896static void 897static void
897dnewcwd(struct directory *dp) 898dnewcwd(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}

cvs diff -r1.33 -r1.34 src/bin/csh/file.c (switch to unified diff)

--- 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
35static char sccsid[] = "@(#)file.c 8.2 (Berkeley) 3/19/94"; 35static 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
80typedef enum { 80typedef enum {
81 LIST, RECOGNIZE 81 LIST, RECOGNIZE
82} COMMAND; 82} COMMAND;
83 83
84static void setup_tty(int); 84static void setup_tty(int);
85static void back_to_col_1(void); 85static void back_to_col_1(void);
86static int pushback(Char *); 86static int pushback(Char *);
87static void catn(Char *, Char *, size_t); 87static void catn(Char *, Char *, size_t);
88static void copyn(Char *, Char *, size_t); 88static void copyn(Char *, Char *, size_t);
89static Char filetype(Char *, Char *); 89static Char filetype(Char *, Char *);
90static void print_by_column(Char *, Char *[], size_t); 90static void print_by_column(Char *, Char *[], size_t);
91static Char *tilde(Char *, Char *); 91static Char *tilde(Char *, Char *);
92static void retype(void); 92static void retype(void);
93static void beep(void); 93static void beep(void);
94static void print_recognized_stuff(Char *); 94static void print_recognized_stuff(Char *);
95static void extract_dir_and_name(Char *, Char *, Char *); 95static void extract_dir_and_name(Char *, Char *, Char *);
96static Char *getentry(DIR *, int); 96static Char *getentry(DIR *, int);
97static void free_items(Char **, size_t); 97static void free_items(Char **, size_t);
98static size_t tsearch(Char *, COMMAND, size_t); 98static size_t tsearch(Char *, COMMAND, size_t);
99static int recognize(Char *, Char *, size_t, size_t); 99static int recognize(Char *, Char *, size_t, size_t);
100static int is_prefix(Char *, Char *); 100static int is_prefix(Char *, Char *);
101static int is_suffix(Char *, Char *); 101static int is_suffix(Char *, Char *);
102static int ignored(Char *); 102static 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 */
109int filec = 0; 109int filec = 0;
110 110
111static void 111static void
112setup_tty(int on) 112setup_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 */
138static void 138static void
139back_to_col_1(void) 139back_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 */
160static int 160static int
161pushback(Char *string) 161pushback(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 */
248static void 248static void
249catn(Char *des, Char *src, size_t count) 249catn(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 */
263static void 263static void
264copyn(Char *des, Char *src, size_t count) 264copyn(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
272static Char 272static Char
273filetype(Char *dir, Char *file) 273filetype(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
299static struct winsize win; 299static struct winsize win;
300 300
301/* 301/*
302 * Print sorted down columns 302 * Print sorted down columns
303 */ 303 */
304static void 304static void
305print_by_column(Char *dir, Char *items[], size_t count) 305print_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 */
346static Char * 346static Char *
347tilde(Char *new, Char *old) 347tilde(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 */
374static void 374static void
375retype(void) 375retype(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
384static void 384static void
385beep(void) 385beep(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 */
395static void 395static void
396print_recognized_stuff(Char *recognized_part) 396print_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 */
424static void 424static void
425extract_dir_and_name(Char *path, Char *dir, Char *name) 425extract_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
440static Char * 440static Char *
441getentry(DIR *dir_fd, int looking_for_lognames) 441getentry(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
456static void 456static void
457free_items(Char **items, size_t numitems) 457free_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 */
479static size_t 479static size_t
480tsearch(Char *word, COMMAND command, size_t max_word_length) 480tsearch(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
510again: /* search for matches */ 510again: /* 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 */
585static int 582static int
586recognize(Char *extended_name, Char *entry, size_t name_length, size_t numitems) 583recognize(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 */
609static int 606static int
610is_prefix(Char *check, Char *template) 607is_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 */
623static int 620static int
624is_suffix(Char *check, Char *template) 621is_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
640ssize_t 637ssize_t
641tenex(Char *inputline, size_t inputline_size) 638tenex(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
715static int 712static int
716ignored(Char *entry) 713ignored(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 */

cvs diff -r1.44 -r1.45 src/bin/csh/func.c (switch to unified diff)

--- 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
35static char sccsid[] = "@(#)func.c 8.1 (Berkeley) 5/31/93"; 35static 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
57extern char **environ; 57extern char **environ;
58extern int progprintf(int, char **); 58extern int progprintf(int, char **);
59 59
60static void islogin(void); 60static void islogin(void);
61static void reexecute(struct command *); 61static void reexecute(struct command *);
62static void preread(void); 62static void preread(void);
63static void doagain(void); 63static void doagain(void);
64static void search(int, int, Char *); 64static void search(int, int, Char *);
65static int getword(Char *); 65static int getword(Char *);
66static int keyword(Char *); 66static int keyword(Char *);
67static void toend(void); 67static void toend(void);
68static void xecho(int, Char **); 68static void xecho(int, Char **);
69static void Unsetenv(Char *); 69static void Unsetenv(Char *);
70static void wpfree(struct whyle *); 70static void wpfree(struct whyle *);
71 71
72struct biltins * 72struct biltins *
73isbfunc(struct command *t) 73isbfunc(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
115void 115void
116func(struct command *t, struct biltins *bp) 116func(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
130void 130void
131/*ARGSUSED*/ 131/*ARGSUSED*/
132doonintr(Char **v, struct command *t) 132doonintr(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
164void 164void
165/*ARGSUSED*/ 165/*ARGSUSED*/
166donohup(Char **v, struct command *t) 166donohup(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
175void 175void
176/*ARGSUSED*/ 176/*ARGSUSED*/
177dozip(Char **v, struct command *t) 177dozip(Char **v, struct command *t)
178{ 178{
179 ; 179 ;
180} 180}
181 181
182void 182void
183prvars(void) 183prvars(void)
184{ 184{
185 plist(&shvhed); 185 plist(&shvhed);
186} 186}
187 187
188void 188void
189/*ARGSUSED*/ 189/*ARGSUSED*/
190doalias(Char **v, struct command *t) 190doalias(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
215void 215void
216/*ARGSUSED*/ 216/*ARGSUSED*/
217unalias(Char **v, struct command *t) 217unalias(Char **v, struct command *t)
218{ 218{
219 unset1(v, &aliases); 219 unset1(v, &aliases);
220} 220}
221 221
222void 222void
223/*ARGSUSED*/ 223/*ARGSUSED*/
224dologout(Char **v, struct command *t) 224dologout(Char **v, struct command *t)
225{ 225{
226 islogin(); 226 islogin();
227 goodbye(); 227 goodbye();
228} 228}
229 229
230void 230void
231/*ARGSUSED*/ 231/*ARGSUSED*/
232dologin(Char **v, struct command *t) 232dologin(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
243static void 243static void
244islogin(void) 244islogin(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
254void 254void
255doif(Char **v, struct command *kp) 255doif(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 */
292static void 292static void
293reexecute(struct command *kp) 293reexecute(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
305void 305void
306/*ARGSUSED*/ 306/*ARGSUSED*/
307doelse(Char **v, struct command *t) 307doelse(Char **v, struct command *t)
308{ 308{
309 search(T_ELSE, 0, NULL); 309 search(T_ELSE, 0, NULL);
310} 310}
311 311
312void 312void
313/*ARGSUSED*/ 313/*ARGSUSED*/
314dogoto(Char **v, struct command *t) 314dogoto(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
322void 322void
323gotolab(Char *lab) 323gotolab(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
344void 344void
345/*ARGSUSED*/ 345/*ARGSUSED*/
346doswitch(Char **v, struct command *t) 346doswitch(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
362void 362void
363/*ARGSUSED*/ 363/*ARGSUSED*/
364dobreak(Char **v, struct command *t) 364dobreak(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
372void 372void
373/*ARGSUSED*/ 373/*ARGSUSED*/
374doexit(Char **v, struct command *t) 374doexit(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
392void 392void
393/*ARGSUSED*/ 393/*ARGSUSED*/
394doforeach(Char **v, struct command *t) 394doforeach(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
433void 433void
434/*ARGSUSED*/ 434/*ARGSUSED*/
435dowhile(Char **v, struct command *t) 435dowhile(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
476static void 476static void
477preread(void) 477preread(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
494void 494void
495/*ARGSUSED*/ 495/*ARGSUSED*/
496doend(Char **v, struct command *t) 496doend(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
504void 504void
505/*ARGSUSED*/ 505/*ARGSUSED*/
506docontin(Char **v, struct command *t) 506docontin(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
513static void 513static void
514doagain(void) 514doagain(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
534void 534void
535dorepeat(Char **v, struct command *kp) 535dorepeat(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
558void 558void
559/*ARGSUSED*/ 559/*ARGSUSED*/
560doswbrk(Char **v, struct command *t) 560doswbrk(Char **v, struct command *t)
561{ 561{
562 search(T_BRKSW, 0, NULL); 562 search(T_BRKSW, 0, NULL);
563} 563}
564 564
565int 565int
566srchx(Char *cp) 566srchx(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
588static Char Stype; 588static Char Stype;
589static Char *Sgoal; 589static Char *Sgoal;
590 590
591/*VARARGS2*/ 591/*VARARGS2*/
592static void 592static void
593search(int type, int level, Char *goal) 593search(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
692static void 692static void
693wpfree(struct whyle *wp) 693wpfree(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
702static int 702static int
703getword(Char *wp) 703getword(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
761past: 761past:
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
793static int 793static int
794keyword(Char *wp) 794keyword(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
810static void 810static void
811toend(void) 811toend(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
823void 823void
824wfree(void) 824wfree(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
856void 856void
857/*ARGSUSED*/ 857/*ARGSUSED*/
858doecho(Char **v, struct command *t) 858doecho(Char **v, struct command *t)
859{ 859{
860 xecho(' ', v); 860 xecho(' ', v);
861} 861}
862 862
863void 863void
864/*ARGSUSED*/ 864/*ARGSUSED*/
865doglob(Char **v, struct command *t) 865doglob(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
871static void 871static void
872xecho(int sep, Char **v) 872xecho(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 }
908done: 908done:
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
919void 919void
920/*ARGSUSED*/ 920/*ARGSUSED*/
921dosetenv(Char **v, struct command *t) 921dosetenv(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
961void 961void
962/*ARGSUSED*/ 962/*ARGSUSED*/
963dounsetenv(Char **v, struct command *t) 963dounsetenv(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
1015void 1015void
1016Setenv(Char *name, Char *val) 1016Setenv(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
1046static void 1046static void
1047Unsetenv(Char *name) 1047Unsetenv(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
1070void 1070void
1071/*ARGSUSED*/ 1071/*ARGSUSED*/
1072doumask(Char **v, struct command *t) 1072doumask(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
1092typedef rlim_t RLIM_TYPE; 1092typedef rlim_t RLIM_TYPE;
1093 1093
1094static const struct limits { 1094static 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
1115static const struct limits *findlim(Char *); 1115static const struct limits *findlim(Char *);
1116static RLIM_TYPE getval(const struct limits *, Char **); 1116static RLIM_TYPE getval(const struct limits *, Char **);
1117static void limtail(Char *, const char *); 1117static void limtail(Char *, const char *);
1118static void plim(const struct limits *, Char); 1118static void plim(const struct limits *, Char);
1119static int setlim(const struct limits *, Char, RLIM_TYPE); 1119static int setlim(const struct limits *, Char, RLIM_TYPE);
1120 1120
1121static const struct limits * 1121static const struct limits *
1122findlim(Char *cp) 1122findlim(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
1139void 1139void
1140/*ARGSUSED*/ 1140/*ARGSUSED*/
1141dolimit(Char **v, struct command *t) 1141dolimit(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
1168static RLIM_TYPE 1168static RLIM_TYPE
1169getval(const struct limits *lp, Char **v) 1169getval(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
1238static void 1238static void
1239limtail(Char *cp, const char *str) 1239limtail(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*/
1249static void 1249static void
1250plim(const struct limits *lp, Char hard) 1250plim(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
1270void 1270void
1271/*ARGSUSED*/ 1271/*ARGSUSED*/
1272dounlimit(Char **v, struct command *t) 1272dounlimit(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
1300static int 1300static int
1301setlim(const struct limits *lp, Char hard, RLIM_TYPE limit) 1301setlim(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
1326void 1326void
1327/*ARGSUSED*/ 1327/*ARGSUSED*/
1328dosuspend(Char **v, struct command *t) 1328dosuspend(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) {
1343retry: 1343retry:
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 */
1368static Char **gv = NULL; 1368static Char **gv = NULL;
1369 1369
1370void 1370void
1371/*ARGSUSED*/ 1371/*ARGSUSED*/
1372doeval(Char **v, struct command *t) 1372doeval(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
1442void 1442void
1443/*ARGSUSED*/ 1443/*ARGSUSED*/
1444doprintf(Char **v, struct command *t) 1444doprintf(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}

cvs diff -r1.31 -r1.32 src/bin/csh/glob.c (switch to unified diff)

--- 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
35static char sccsid[] = "@(#)glob.c 8.1 (Berkeley) 5/31/93"; 35static 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
54static int noglob; 54static int noglob;
55static int gargsiz, pargsiz; 55static 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
72Char **gargv = NULL; 72Char **gargv = NULL;
73Char **pargv = NULL; 73Char **pargv = NULL;
74long gargc = 0; 74long gargc = 0;
75long pargc = 0; 75long 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 */
86static Char *globtilde(Char **, Char *); 86static Char *globtilde(Char **, Char *);
87static Char *handleone(Char *, Char **, int); 87static Char *handleone(Char *, Char **, int);
88static Char **libglob(Char **); 88static Char **libglob(Char **);
89static Char **globexpand(Char **); 89static Char **globexpand(Char **);
90static int globbrace(Char *, Char *, Char ***); 90static int globbrace(Char *, Char *, Char ***);
91static void expbrace(Char ***, Char ***, size_t); 91static void expbrace(Char ***, Char ***, size_t);
92static int pmatch(const Char *, const Char *); 92static int pmatch(const Char *, const Char *);
93static void pword(void); 93static void pword(void);
94static void psave(int); 94static void psave(int);
95static void backeval(Char *, int); 95static void backeval(Char *, int);
96 96
97static Char * 97static Char *
98globtilde(Char **nv, Char *s) 98globtilde(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
126static int 126static int
127globbrace(Char *s, Char *p, Char ***bl) 127globbrace(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
213static void 213static void
214expbrace(Char ***nvp, Char ***elp, size_t size) 214expbrace(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
275static Char ** 275static Char **
276globexpand(Char **v) 276globexpand(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
335static Char * 335static Char *
336handleone(Char *str, Char **vl, int action) 336handleone(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
369static Char ** 369static Char **
370libglob(Char **vl) 370libglob(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
417Char * 417Char *
418globone(Char *str, int action) 418globone(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
476Char ** 476Char **
477globall(Char **v) 477globall(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
511void 511void
512ginit(void) 512ginit(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
520void 520void
521rscan(Char **t, void (*f)(int)) 521rscan(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
530void 530void
531trim(Char **t) 531trim(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
540void 540void
541tglob(Char **t) 541tglob(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 */
582Char ** 582Char **
583dobackp(Char *cp, int literal) 583dobackp(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
626static void 626static void
627backeval(Char *cp, int literal) 627backeval(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
766static void 766static void
767psave(int c) 767psave(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
774static void 774static void
775pword(void) 775pword(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
788int  788int
789Gmatch(Char *string, Char *pattern) 789Gmatch(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
815static int 815static int
816pmatch(const Char *name, const Char *pat) 816pmatch(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
887void 887void
888Gcat(Char *s1, Char *s2) 888Gcat(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
911int 911int
912sortscmp(const void *va, const void *vb) 912sortscmp(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 */

cvs diff -r1.22 -r1.23 src/bin/csh/misc.c (switch to unified diff)

--- 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
35static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 5/31/93"; 35static 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
52static int renum(int, int); 52static int renum(int, int);
53 53
54int 54int
55any(const char *s, int c) 55any(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
65char * 65char *
66strsave(const char *s) 66strsave(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
81Char ** 81Char **
82blkend(Char **up) 82blkend(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
90void 90void
91blkpr(FILE *fp, Char **av) 91blkpr(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
100int 100int
101blklen(Char **av) 101blklen(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
111Char ** 111Char **
112blkcpy(Char **oav, Char **bv) 112blkcpy(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
122Char ** 122Char **
123blkcat(Char **up, Char **vp) 123blkcat(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
129void 129void
130blkfree(Char **av0) 130blkfree(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
142Char ** 142Char **
143saveblk(Char **v) 143saveblk(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
158char * 158char *
159strstr(char *s, char *t) 159strstr(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
179char * 179char *
180strspl(char *cp, char *dp) 180strspl(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
202Char ** 202Char **
203blkspl(Char **up, Char **vp) 203blkspl(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
212Char 212Char
213lastchr(Char *cp) 213lastchr(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 */
228void 228void
229closem(void) 229closem(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
246void 246void
247donefds(void) 247donefds(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 */
261int 261int
262dmove(int i, int j) 262dmove(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
278int 278int
279dcopy(int i, int j) 279dcopy(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
290static int 290static int
291renum(int i, int j) 291renum(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 */
313void 313void
314lshift(Char **v, size_t c) 314lshift(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
323int 323int
324number(Char *cp) 324number(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
339Char ** 339Char **
340copyblk(Char **v) 340copyblk(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
350char * 350char *
351strend(char *cp) 351strend(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
362Char * 362Char *
363strip(Char *cp) 363strip(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
375Char * 375Char *
376quote(Char *cp) 376quote(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
388void 388void
389udvar(Char *name) 389udvar(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
396int 396int
397prefix(Char *sub, Char *str) 397prefix(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}

cvs diff -r1.16 -r1.17 src/bin/csh/str.c (switch to unified diff)

--- 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
35static char sccsid[] = "@(#)str.c 8.1 (Berkeley) 5/31/93"; 35static 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
58Char ** 58Char **
59blk2short(char **src) 59blk2short(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
77char ** 77char **
78short2blk(Char *const *src) 78short2blk(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
96Char * 96Char *
97str2short(const char *src) 97str2short(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
126char * 126char *
127short2str(const Char *src) 127short2str(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
155Char * 155Char *
156s_strcpy(Char *dst, const Char *src) 156s_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
166Char * 166Char *
167s_strncpy(Char *dst, const Char *src, size_t n) 167s_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
185Char * 185Char *
186s_strcat(Char *dst, const Char *src) 186s_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
200Char * 200Char *
201s_strncat(Char *dst, Char *src, size_t n) 201s_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
226Char * 226Char *
227s_strchr(const Char *str, int ch) 227s_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
236Char * 236Char *
237s_strrchr(const Char *str, int ch) 237s_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
249size_t 249size_t
250s_strlen(const Char *str) 250s_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
259int 259int
260s_strcmp(const Char *str1, const Char *str2) 260s_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
279int 279int
280s_strncmp(const Char *str1, const Char *str2, size_t n) 280s_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
305Char * 305Char *
306s_strsave(const Char *s) 306s_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
321Char * 321Char *
322s_strspl(const Char *cp, const Char *dp) 322s_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
343Char * 343Char *
344s_strend(const Char *cp) 344s_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
353Char * 353Char *
354s_strstr(const Char *s, const Char *t) 354s_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
369char * 369char *
370short2qstr(const Char *src) 370short2qstr(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 */
411char * 411char *
412vis_str(const Char *cp) 412vis_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}