]> git.ipfire.org Git - thirdparty/bash.git/blame - general.c
Bash-5.2 patch 26: fix typo when specifying readline's custom color prefix
[thirdparty/bash.git] / general.c
CommitLineData
726f6388
JA
1/* general.c -- Stuff that is used by all files. */
2
74091dd4 3/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
726f6388
JA
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
3185942a
JA
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
726f6388 11
3185942a
JA
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
726f6388 16
3185942a
JA
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19*/
726f6388 20
ccc6cda3
JA
21#include "config.h"
22
726f6388 23#include "bashtypes.h"
ac50fbac 24#if defined (HAVE_SYS_PARAM_H)
cce855bc
JA
25# include <sys/param.h>
26#endif
ccc6cda3
JA
27#include "posixstat.h"
28
29#if defined (HAVE_UNISTD_H)
30# include <unistd.h>
31#endif
32
726f6388
JA
33#include "filecntl.h"
34#include "bashansi.h"
ccc6cda3 35#include <stdio.h>
f73dda09 36#include "chartypes.h"
ccc6cda3
JA
37#include <errno.h>
38
b80f6443
JA
39#include "bashintl.h"
40
726f6388 41#include "shell.h"
d233b485
CR
42#include "parser.h"
43#include "flags.h"
44#include "findcmd.h"
95732b49 45#include "test.h"
ac50fbac 46#include "trap.h"
8868edaf 47#include "pathexp.h"
95732b49 48
d233b485
CR
49#include "builtins/common.h"
50
a0c0a00f
CR
51#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
52# include <mbstr.h> /* mbschr */
53#endif
54
726f6388
JA
55#include <tilde/tilde.h>
56
726f6388
JA
57#if !defined (errno)
58extern int errno;
59#endif /* !errno */
60
d233b485
CR
61#ifdef __CYGWIN__
62# include <sys/cygwin.h>
63#endif
cce855bc 64
8868edaf
CR
65static char *bash_special_tilde_expansions PARAMS((char *));
66static int unquoted_tilde_word PARAMS((const char *));
67static void initialize_group_array PARAMS((void));
7117c2d2 68
cce855bc 69/* A standard error message to use when getcwd() returns NULL. */
3185942a 70const char * const bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
726f6388 71
d233b485
CR
72/* Do whatever is necessary to initialize `Posix mode'. This currently
73 modifies the following variables which are controlled via shopt:
74 interactive_comments
75 source_uses_path
76 expand_aliases
77 inherit_errexit
78 print_shift_error
8868edaf 79 posixglob
d233b485
CR
80
81 and the following variables which cannot be user-modified:
82
83 source_searches_cwd
84
85 If we add to the first list, we need to change the table and functions
86 below */
87
88static struct {
89 int *posix_mode_var;
90} posix_vars[] =
91{
92 &interactive_comments,
93 &source_uses_path,
8c9524f9 94 &expaliases_flag,
d233b485
CR
95 &inherit_errexit,
96 &print_shift_error,
97 0
98};
99
8868edaf
CR
100static char *saved_posix_vars = 0;
101
726f6388 102void
ccc6cda3
JA
103posix_initialize (on)
104 int on;
726f6388 105{
28ef6c31
JA
106 /* Things that should be turned on when posix mode is enabled. */
107 if (on != 0)
108 {
8c9524f9
CR
109 interactive_comments = source_uses_path = 1;
110 expand_aliases = expaliases_flag = 1;
a0c0a00f 111 inherit_errexit = 1;
3185942a 112 source_searches_cwd = 0;
d233b485 113 print_shift_error = 1;
28ef6c31
JA
114 }
115
116 /* Things that should be turned on when posix mode is disabled. */
8868edaf
CR
117 else if (saved_posix_vars) /* on == 0, restore saved settings */
118 {
119 set_posix_options (saved_posix_vars);
8c9524f9 120 expand_aliases = expaliases_flag;
8868edaf
CR
121 free (saved_posix_vars);
122 saved_posix_vars = 0;
123 }
124 else /* on == 0, restore a default set of settings */
28ef6c31
JA
125 {
126 source_searches_cwd = 1;
8c9524f9 127 expand_aliases = expaliases_flag = interactive_shell; /* XXX */
d233b485 128 print_shift_error = 0;
28ef6c31 129 }
726f6388
JA
130}
131
d233b485
CR
132int
133num_posix_options ()
134{
135 return ((sizeof (posix_vars) / sizeof (posix_vars[0])) - 1);
136}
137
138char *
139get_posix_options (bitmap)
140 char *bitmap;
141{
142 register int i;
143
144 if (bitmap == 0)
145 bitmap = (char *)xmalloc (num_posix_options ()); /* no trailing NULL */
146 for (i = 0; posix_vars[i].posix_mode_var; i++)
147 bitmap[i] = *(posix_vars[i].posix_mode_var);
148 return bitmap;
149}
150
8868edaf
CR
151#undef save_posix_options
152void
153save_posix_options ()
154{
155 saved_posix_vars = get_posix_options (saved_posix_vars);
156}
157
d233b485
CR
158void
159set_posix_options (bitmap)
160 const char *bitmap;
161{
162 register int i;
163
164 for (i = 0; posix_vars[i].posix_mode_var; i++)
165 *(posix_vars[i].posix_mode_var) = bitmap[i];
166}
167
ccc6cda3
JA
168/* **************************************************************** */
169/* */
170/* Functions to convert to and from and display non-standard types */
171/* */
172/* **************************************************************** */
173
726f6388
JA
174#if defined (RLIMTYPE)
175RLIMTYPE
176string_to_rlimtype (s)
177 char *s;
178{
cce855bc
JA
179 RLIMTYPE ret;
180 int neg;
726f6388 181
cce855bc
JA
182 ret = 0;
183 neg = 0;
726f6388
JA
184 while (s && *s && whitespace (*s))
185 s++;
0001803f 186 if (s && (*s == '-' || *s == '+'))
726f6388
JA
187 {
188 neg = *s == '-';
189 s++;
190 }
f73dda09
JA
191 for ( ; s && *s && DIGIT (*s); s++)
192 ret = (ret * 10) + TODIGIT (*s);
726f6388
JA
193 return (neg ? -ret : ret);
194}
195
196void
197print_rlimtype (n, addnl)
198 RLIMTYPE n;
199 int addnl;
200{
f73dda09 201 char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p;
726f6388 202
f73dda09
JA
203 p = s + sizeof(s);
204 *--p = '\0';
726f6388
JA
205
206 if (n < 0)
207 {
f73dda09
JA
208 do
209 *--p = '0' - n % 10;
210 while ((n /= 10) != 0);
211
212 *--p = '-';
213 }
214 else
215 {
216 do
217 *--p = '0' + n % 10;
218 while ((n /= 10) != 0);
726f6388
JA
219 }
220
f73dda09 221 printf ("%s%s", p, addnl ? "\n" : "");
726f6388
JA
222}
223#endif /* RLIMTYPE */
224
ccc6cda3
JA
225/* **************************************************************** */
226/* */
227/* Input Validation Functions */
228/* */
229/* **************************************************************** */
230
231/* Return non-zero if all of the characters in STRING are digits. */
232int
233all_digits (string)
a0c0a00f 234 const char *string;
ccc6cda3 235{
a0c0a00f 236 register const char *s;
28ef6c31
JA
237
238 for (s = string; *s; s++)
f73dda09 239 if (DIGIT (*s) == 0)
28ef6c31
JA
240 return (0);
241
ccc6cda3
JA
242 return (1);
243}
244
245/* Return non-zero if the characters pointed to by STRING constitute a
246 valid number. Stuff the converted number into RESULT if RESULT is
f73dda09 247 not null. */
ccc6cda3
JA
248int
249legal_number (string, result)
3185942a 250 const char *string;
7117c2d2 251 intmax_t *result;
ccc6cda3 252{
7117c2d2 253 intmax_t value;
cce855bc 254 char *ep;
ccc6cda3
JA
255
256 if (result)
257 *result = 0;
258
ac50fbac
CR
259 if (string == 0)
260 return 0;
261
f73dda09 262 errno = 0;
7117c2d2 263 value = strtoimax (string, &ep, 10);
3185942a 264 if (errno || ep == string)
f73dda09 265 return 0; /* errno is set on overflow or underflow */
ccc6cda3 266
7117c2d2 267 /* Skip any trailing whitespace, since strtoimax does not. */
28ef6c31
JA
268 while (whitespace (*ep))
269 ep++;
270
cce855bc
JA
271 /* If *string is not '\0' but *ep is '\0' on return, the entire string
272 is valid. */
ac50fbac 273 if (*string && *ep == '\0')
ccc6cda3
JA
274 {
275 if (result)
cce855bc
JA
276 *result = value;
277 /* The SunOS4 implementation of strtol() will happily ignore
278 overflow conditions, so this cannot do overflow correctly
279 on those systems. */
280 return 1;
ccc6cda3 281 }
cce855bc
JA
282
283 return (0);
ccc6cda3
JA
284}
285
726f6388
JA
286/* Return 1 if this token is a legal shell `identifier'; that is, it consists
287 solely of letters, digits, and underscores, and does not begin with a
288 digit. */
289int
290legal_identifier (name)
a0c0a00f 291 const char *name;
726f6388 292{
a0c0a00f 293 register const char *s;
f73dda09 294 unsigned char c;
726f6388 295
f73dda09 296 if (!name || !(c = *name) || (legal_variable_starter (c) == 0))
726f6388
JA
297 return (0);
298
f73dda09 299 for (s = name + 1; (c = *s) != 0; s++)
726f6388 300 {
f73dda09 301 if (legal_variable_char (c) == 0)
28ef6c31 302 return (0);
726f6388
JA
303 }
304 return (1);
305}
306
a0c0a00f
CR
307/* Return 1 if NAME is a valid value that can be assigned to a nameref
308 variable. FLAGS can be 2, in which case the name is going to be used
309 to create a variable. Other values are currently unused, but could
310 be used to allow values to be stored and indirectly referenced, but
311 not used in assignments. */
312int
313valid_nameref_value (name, flags)
314 const char *name;
315 int flags;
316{
317 if (name == 0 || *name == 0)
318 return 0;
319
320 /* valid identifier */
321#if defined (ARRAY_VARS)
322 if (legal_identifier (name) || (flags != 2 && valid_array_reference (name, 0)))
323#else
324 if (legal_identifier (name))
325#endif
326 return 1;
327
328 return 0;
329}
330
331int
332check_selfref (name, value, flags)
333 const char *name;
334 char *value;
335 int flags;
336{
337 char *t;
338
339 if (STREQ (name, value))
340 return 1;
341
342#if defined (ARRAY_VARS)
343 if (valid_array_reference (value, 0))
344 {
d233b485 345 t = array_variable_name (value, 0, (char **)NULL, (int *)NULL);
a0c0a00f
CR
346 if (t && STREQ (name, t))
347 {
348 free (t);
349 return 1;
350 }
351 free (t);
352 }
353#endif
354
355 return 0; /* not a self reference */
356}
357
726f6388 358/* Make sure that WORD is a valid shell identifier, i.e.
8868edaf
CR
359 does not contain a dollar sign, nor is quoted in any way.
360 If CHECK_WORD is non-zero,
726f6388 361 the word is checked to ensure that it consists of only letters,
8868edaf 362 digits, and underscores, and does not consist of all digits. */
ccc6cda3 363int
726f6388
JA
364check_identifier (word, check_word)
365 WORD_DESC *word;
366 int check_word;
367{
8868edaf 368 if (word->flags & (W_HASDOLLAR|W_QUOTED)) /* XXX - HASDOLLAR? */
726f6388 369 {
b80f6443 370 internal_error (_("`%s': not a valid identifier"), word->word);
726f6388
JA
371 return (0);
372 }
8868edaf 373 else if (check_word && (all_digits (word->word) || legal_identifier (word->word) == 0))
726f6388 374 {
b80f6443 375 internal_error (_("`%s': not a valid identifier"), word->word);
726f6388
JA
376 return (0);
377 }
378 else
379 return (1);
380}
381
a0c0a00f
CR
382/* Return 1 if STRING is a function name that the shell will import from
383 the environment. Currently we reject attempts to import shell functions
384 containing slashes, beginning with newlines or containing blanks. In
385 Posix mode, we require that STRING be a valid shell identifier. Not
386 used yet. */
387int
388importable_function_name (string, len)
389 const char *string;
390 size_t len;
391{
392 if (absolute_program (string)) /* don't allow slash */
393 return 0;
394 if (*string == '\n') /* can't start with a newline */
395 return 0;
396 if (shellblank (*string) || shellblank(string[len-1]))
397 return 0;
398 return (posixly_correct ? legal_identifier (string) : 1);
399}
400
401int
402exportable_function_name (string)
403 const char *string;
404{
405 if (absolute_program (string))
406 return 0;
407 if (mbschr (string, '=') != 0)
408 return 0;
409 return 1;
410}
411
b80f6443
JA
412/* Return 1 if STRING comprises a valid alias name. The shell accepts
413 essentially all characters except those which must be quoted to the
414 parser (which disqualifies them from alias expansion anyway) and `/'. */
415int
416legal_alias_name (string, flags)
a0c0a00f 417 const char *string;
b80f6443
JA
418 int flags;
419{
a0c0a00f 420 register const char *s;
b80f6443
JA
421
422 for (s = string; *s; s++)
423 if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/'))
424 return 0;
425 return 1;
426}
427
7117c2d2 428/* Returns non-zero if STRING is an assignment statement. The returned value
d233b485 429 is the index of the `=' sign. If FLAGS&1 we are expecting a compound assignment
8868edaf
CR
430 and require an array subscript before the `=' to denote an assignment
431 statement. */
7117c2d2 432int
b80f6443 433assignment (string, flags)
7117c2d2 434 const char *string;
b80f6443 435 int flags;
7117c2d2
JA
436{
437 register unsigned char c;
438 register int newi, indx;
439
440 c = string[indx = 0];
441
b80f6443 442#if defined (ARRAY_VARS)
8868edaf
CR
443 /* If parser_state includes PST_COMPASSIGN, FLAGS will include 1, so we are
444 parsing the contents of a compound assignment. If parser_state includes
445 PST_REPARSE, we are in the middle of an assignment statement and breaking
446 the words between the parens into words and assignment statements, but
447 we don't need to check for that right now. Within a compound assignment,
448 the subscript is required to make the word an assignment statement. If
449 we don't have a subscript, even if the word is a valid assignment
450 statement otherwise, we don't want to treat it as one. */
451 if ((flags & 1) && c != '[') /* ] */
452 return (0);
453 else if ((flags & 1) == 0 && legal_variable_starter (c) == 0)
b80f6443 454#else
7117c2d2 455 if (legal_variable_starter (c) == 0)
b80f6443 456#endif
7117c2d2
JA
457 return (0);
458
459 while (c = string[indx])
460 {
461 /* The following is safe. Note that '=' at the start of a word
462 is not an assignment statement. */
463 if (c == '=')
464 return (indx);
465
466#if defined (ARRAY_VARS)
467 if (c == '[')
468 {
d233b485
CR
469 newi = skipsubscript (string, indx, (flags & 2) ? 1 : 0);
470 /* XXX - why not check for blank subscripts here, if we do in
471 valid_array_reference? */
7117c2d2
JA
472 if (string[newi++] != ']')
473 return (0);
95732b49
JA
474 if (string[newi] == '+' && string[newi+1] == '=')
475 return (newi + 1);
7117c2d2
JA
476 return ((string[newi] == '=') ? newi : 0);
477 }
478#endif /* ARRAY_VARS */
479
95732b49
JA
480 /* Check for `+=' */
481 if (c == '+' && string[indx+1] == '=')
482 return (indx + 1);
483
7117c2d2
JA
484 /* Variable names in assignment statements may contain only letters,
485 digits, and `_'. */
486 if (legal_variable_char (c) == 0)
487 return (0);
488
489 indx++;
490 }
491 return (0);
492}
493
d233b485
CR
494int
495line_isblank (line)
496 const char *line;
497{
498 register int i;
499
500 if (line == 0)
501 return 0; /* XXX */
502 for (i = 0; line[i]; i++)
503 if (isblank ((unsigned char)line[i]) == 0)
504 break;
505 return (line[i] == '\0');
506}
507
ccc6cda3
JA
508/* **************************************************************** */
509/* */
510/* Functions to manage files and file descriptors */
511/* */
512/* **************************************************************** */
513
726f6388
JA
514/* A function to unset no-delay mode on a file descriptor. Used in shell.c
515 to unset it on the fd passed as stdin. Should be called on stdin if
516 readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
517
518#if !defined (O_NDELAY)
519# if defined (FNDELAY)
520# define O_NDELAY FNDELAY
521# endif
522#endif /* O_NDELAY */
523
524/* Make sure no-delay mode is not set on file descriptor FD. */
bb70624e 525int
28ef6c31 526sh_unset_nodelay_mode (fd)
726f6388
JA
527 int fd;
528{
bb70624e 529 int flags, bflags;
726f6388
JA
530
531 if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
bb70624e 532 return -1;
726f6388 533
bb70624e 534 bflags = 0;
ccc6cda3
JA
535
536 /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
537 and O_NDELAY is defined. */
bb70624e
JA
538#ifdef O_NONBLOCK
539 bflags |= O_NONBLOCK;
540#endif
541
542#ifdef O_NDELAY
543 bflags |= O_NDELAY;
544#endif
545
546 if (flags & bflags)
726f6388 547 {
bb70624e
JA
548 flags &= ~bflags;
549 return (fcntl (fd, F_SETFL, flags));
726f6388 550 }
726f6388 551
bb70624e 552 return 0;
726f6388
JA
553}
554
d233b485
CR
555/* Just a wrapper for the define in include/filecntl.h */
556int
557sh_setclexec (fd)
558 int fd;
559{
560 return (SET_CLOSE_ON_EXEC (fd));
561}
562
7117c2d2
JA
563/* Return 1 if file descriptor FD is valid; 0 otherwise. */
564int
565sh_validfd (fd)
566 int fd;
567{
568 return (fcntl (fd, F_GETFD, 0) >= 0);
569}
570
495aee44
CR
571int
572fd_ispipe (fd)
573 int fd;
574{
575 errno = 0;
a0c0a00f 576 return ((lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE));
495aee44
CR
577}
578
b72432fd
JA
579/* There is a bug in the NeXT 2.1 rlogind that causes opens
580 of /dev/tty to fail. */
581
582#if defined (__BEOS__)
583/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it
584 into a no-op. This should probably go away in the future. */
585# undef O_NONBLOCK
586# define O_NONBLOCK 0
587#endif /* __BEOS__ */
588
726f6388 589void
ccc6cda3 590check_dev_tty ()
726f6388 591{
ccc6cda3
JA
592 int tty_fd;
593 char *tty;
726f6388 594
d166f048 595 tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
726f6388 596
ccc6cda3 597 if (tty_fd < 0)
726f6388 598 {
ccc6cda3
JA
599 tty = (char *)ttyname (fileno (stdin));
600 if (tty == 0)
601 return;
d166f048 602 tty_fd = open (tty, O_RDWR|O_NONBLOCK);
726f6388 603 }
ac50fbac
CR
604 if (tty_fd >= 0)
605 close (tty_fd);
726f6388
JA
606}
607
ccc6cda3
JA
608/* Return 1 if PATH1 and PATH2 are the same file. This is kind of
609 expensive. If non-NULL STP1 and STP2 point to stat structures
610 corresponding to PATH1 and PATH2, respectively. */
726f6388 611int
ccc6cda3 612same_file (path1, path2, stp1, stp2)
a0c0a00f 613 const char *path1, *path2;
ccc6cda3 614 struct stat *stp1, *stp2;
726f6388 615{
ccc6cda3 616 struct stat st1, st2;
726f6388 617
ccc6cda3 618 if (stp1 == NULL)
726f6388 619 {
ccc6cda3
JA
620 if (stat (path1, &st1) != 0)
621 return (0);
622 stp1 = &st1;
726f6388 623 }
726f6388 624
ccc6cda3
JA
625 if (stp2 == NULL)
626 {
627 if (stat (path2, &st2) != 0)
628 return (0);
629 stp2 = &st2;
630 }
726f6388 631
ccc6cda3 632 return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
726f6388
JA
633}
634
ccc6cda3
JA
635/* Move FD to a number close to the maximum number of file descriptors
636 allowed in the shell process, to avoid the user stepping on it with
637 redirection and causing us extra work. If CHECK_NEW is non-zero,
638 we check whether or not the file descriptors are in use before
d166f048
JA
639 duplicating FD onto them. MAXFD says where to start checking the
640 file descriptors. If it's less than 20, we get the maximum value
641 available from getdtablesize(2). */
726f6388 642int
d166f048
JA
643move_to_high_fd (fd, check_new, maxfd)
644 int fd, check_new, maxfd;
726f6388 645{
ccc6cda3 646 int script_fd, nfds, ignore;
726f6388 647
d166f048
JA
648 if (maxfd < 20)
649 {
650 nfds = getdtablesize ();
651 if (nfds <= 0)
652 nfds = 20;
7117c2d2
JA
653 if (nfds > HIGH_FD_MAX)
654 nfds = HIGH_FD_MAX; /* reasonable maximum */
d166f048
JA
655 }
656 else
657 nfds = maxfd;
726f6388 658
ccc6cda3
JA
659 for (nfds--; check_new && nfds > 3; nfds--)
660 if (fcntl (nfds, F_GETFD, &ignore) == -1)
661 break;
726f6388 662
7117c2d2 663 if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
ccc6cda3
JA
664 {
665 if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */
666 close (fd);
667 return (script_fd);
668 }
726f6388 669
7117c2d2
JA
670 /* OK, we didn't find one less than our artificial maximum; return the
671 original file descriptor. */
ccc6cda3
JA
672 return (fd);
673}
674
675/* Return non-zero if the characters from SAMPLE are not all valid
676 characters to be found in the first line of a shell script. We
677 check up to the first newline, or SAMPLE_LEN, whichever comes first.
678 All of the characters must be printable or whitespace. */
726f6388 679
726f6388 680int
ccc6cda3 681check_binary_file (sample, sample_len)
a0c0a00f 682 const char *sample;
ccc6cda3 683 int sample_len;
726f6388 684{
ccc6cda3 685 register int i;
6014c93f 686 int nline;
f73dda09 687 unsigned char c;
726f6388 688
74091dd4
CR
689 if (sample_len >= 4 && sample[0] == 0x7f && sample[1] == 'E' && sample[2] == 'L' && sample[3] == 'F')
690 return 1;
691
692 /* Generally we check the first line for NULs. If the first line looks like
6014c93f
CR
693 a `#!' interpreter specifier, we look for NULs in the first two lines. */
694 nline = (sample[0] == '#' && sample[1] == '!') ? 2 : 1;
74091dd4 695
ccc6cda3
JA
696 for (i = 0; i < sample_len; i++)
697 {
f73dda09 698 c = sample[i];
6014c93f 699 if (c == '\n' && --nline == 0)
ccc6cda3 700 return (0);
0628567a 701 if (c == '\0')
ccc6cda3
JA
702 return (1);
703 }
726f6388 704
ccc6cda3 705 return (0);
726f6388
JA
706}
707
3185942a
JA
708/* **************************************************************** */
709/* */
710/* Functions to manipulate pipes */
711/* */
712/* **************************************************************** */
713
714int
715sh_openpipe (pv)
716 int *pv;
717{
718 int r;
719
720 if ((r = pipe (pv)) < 0)
721 return r;
722
723 pv[0] = move_to_high_fd (pv[0], 1, 64);
724 pv[1] = move_to_high_fd (pv[1], 1, 64);
725
726 return 0;
727}
728
729int
730sh_closepipe (pv)
731 int *pv;
732{
733 if (pv[0] >= 0)
734 close (pv[0]);
735
736 if (pv[1] >= 0)
737 close (pv[1]);
738
739 pv[0] = pv[1] = -1;
740 return 0;
741}
742
b80f6443
JA
743/* **************************************************************** */
744/* */
745/* Functions to inspect pathnames */
746/* */
747/* **************************************************************** */
748
3185942a
JA
749int
750file_exists (fn)
a0c0a00f 751 const char *fn;
3185942a
JA
752{
753 struct stat sb;
754
755 return (stat (fn, &sb) == 0);
756}
757
b80f6443
JA
758int
759file_isdir (fn)
a0c0a00f 760 const char *fn;
b80f6443
JA
761{
762 struct stat sb;
763
764 return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode));
765}
766
767int
768file_iswdir (fn)
a0c0a00f 769 const char *fn;
b80f6443 770{
0628567a 771 return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0);
b80f6443
JA
772}
773
495aee44
CR
774/* Return 1 if STRING is "." or "..", optionally followed by a directory
775 separator */
776int
ac50fbac 777path_dot_or_dotdot (string)
495aee44
CR
778 const char *string;
779{
780 if (string == 0 || *string == '\0' || *string != '.')
781 return (0);
782
783 /* string[0] == '.' */
784 if (PATHSEP(string[1]) || (string[1] == '.' && PATHSEP(string[2])))
785 return (1);
786
787 return (0);
788}
789
95732b49
JA
790/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd'
791 to decide whether or not to look up a directory name in $CDPATH. */
792int
793absolute_pathname (string)
794 const char *string;
795{
796 if (string == 0 || *string == '\0')
797 return (0);
798
799 if (ABSPATH(string))
800 return (1);
801
802 if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */
803 return (1);
804
805 if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */
806 return (1);
807
808 return (0);
809}
810
811/* Return 1 if STRING is an absolute program name; it is absolute if it
812 contains any slashes. This is used to decide whether or not to look
813 up through $PATH. */
814int
815absolute_program (string)
816 const char *string;
817{
0001803f 818 return ((char *)mbschr (string, '/') != (char *)NULL);
95732b49 819}
b80f6443 820
ccc6cda3
JA
821/* **************************************************************** */
822/* */
823/* Functions to manipulate pathnames */
824/* */
825/* **************************************************************** */
726f6388 826
726f6388
JA
827/* Turn STRING (a pathname) into an absolute pathname, assuming that
828 DOT_PATH contains the symbolic location of `.'. This always
829 returns a new string, even if STRING was an absolute pathname to
830 begin with. */
831char *
832make_absolute (string, dot_path)
a0c0a00f 833 const char *string, *dot_path;
726f6388
JA
834{
835 char *result;
ccc6cda3 836
28ef6c31 837 if (dot_path == 0 || ABSPATH(string))
b80f6443
JA
838#ifdef __CYGWIN__
839 {
840 char pathbuf[PATH_MAX + 1];
841
d233b485
CR
842 /* WAS cygwin_conv_to_full_posix_path (string, pathbuf); */
843 cygwin_conv_path (CCP_WIN_A_TO_POSIX, string, pathbuf, PATH_MAX);
b80f6443
JA
844 result = savestring (pathbuf);
845 }
846#else
726f6388 847 result = savestring (string);
b80f6443 848#endif
726f6388 849 else
bb70624e 850 result = sh_makepath (dot_path, string, 0);
726f6388
JA
851
852 return (result);
853}
854
726f6388 855/* Return the `basename' of the pathname in STRING (the stuff after the
95732b49 856 last '/'). If STRING is `/', just return it. */
726f6388
JA
857char *
858base_pathname (string)
859 char *string;
860{
861 char *p;
862
95732b49 863#if 0
28ef6c31 864 if (absolute_pathname (string) == 0)
726f6388 865 return (string);
95732b49
JA
866#endif
867
868 if (string[0] == '/' && string[1] == 0)
869 return (string);
726f6388
JA
870
871 p = (char *)strrchr (string, '/');
ccc6cda3 872 return (p ? ++p : string);
726f6388
JA
873}
874
875/* Return the full pathname of FILE. Easy. Filenames that begin
876 with a '/' are returned as themselves. Other filenames have
877 the current working directory prepended. A new string is
878 returned in either case. */
879char *
880full_pathname (file)
881 char *file;
882{
bb70624e 883 char *ret;
726f6388 884
7117c2d2 885 file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
726f6388 886
28ef6c31 887 if (ABSPATH(file))
726f6388
JA
888 return (file);
889
bb70624e
JA
890 ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT));
891 free (file);
726f6388 892
bb70624e 893 return (ret);
726f6388 894}
726f6388
JA
895
896/* A slightly related function. Get the prettiest name of this
897 directory possible. */
ccc6cda3 898static char tdir[PATH_MAX];
726f6388
JA
899
900/* Return a pretty pathname. If the first part of the pathname is
901 the same as $HOME, then replace that with `~'. */
902char *
903polite_directory_format (name)
904 char *name;
905{
ccc6cda3
JA
906 char *home;
907 int l;
726f6388 908
ccc6cda3
JA
909 home = get_string_value ("HOME");
910 l = home ? strlen (home) : 0;
726f6388
JA
911 if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
912 {
e8ce775d 913 strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
726f6388 914 tdir[0] = '~';
e8ce775d 915 tdir[sizeof(tdir) - 1] = '\0';
726f6388
JA
916 return (tdir);
917 }
918 else
919 return (name);
920}
921
3185942a
JA
922/* Trim NAME. If NAME begins with `~/', skip over tilde prefix. Trim to
923 keep any tilde prefix and PROMPT_DIRTRIM trailing directory components
924 and replace the intervening characters with `...' */
925char *
926trim_pathname (name, maxlen)
927 char *name;
928 int maxlen;
929{
930 int nlen, ndirs;
931 intmax_t nskip;
932 char *nbeg, *nend, *ntail, *v;
933
934 if (name == 0 || (nlen = strlen (name)) == 0)
935 return name;
936 nend = name + nlen;
937
938 v = get_string_value ("PROMPT_DIRTRIM");
939 if (v == 0 || *v == 0)
940 return name;
941 if (legal_number (v, &nskip) == 0 || nskip <= 0)
942 return name;
943
944 /* Skip over tilde prefix */
945 nbeg = name;
946 if (name[0] == '~')
947 for (nbeg = name; *nbeg; nbeg++)
948 if (*nbeg == '/')
949 {
950 nbeg++;
951 break;
952 }
953 if (*nbeg == 0)
954 return name;
955
956 for (ndirs = 0, ntail = nbeg; *ntail; ntail++)
957 if (*ntail == '/')
958 ndirs++;
0001803f 959 if (ndirs < nskip)
3185942a
JA
960 return name;
961
962 for (ntail = (*nend == '/') ? nend : nend - 1; ntail > nbeg; ntail--)
963 {
964 if (*ntail == '/')
965 nskip--;
966 if (nskip == 0)
967 break;
968 }
969 if (ntail == nbeg)
970 return name;
971
972 /* Now we want to return name[0..nbeg]+"..."+ntail, modifying name in place */
973 nlen = ntail - nbeg;
974 if (nlen <= 3)
975 return name;
976
977 *nbeg++ = '.';
978 *nbeg++ = '.';
979 *nbeg++ = '.';
980
981 nlen = nend - ntail;
ac50fbac 982 memmove (nbeg, ntail, nlen);
3185942a
JA
983 nbeg[nlen] = '\0';
984
985 return name;
986}
987
a0c0a00f
CR
988/* Return a printable representation of FN without special characters. The
989 caller is responsible for freeing memory if this returns something other
990 than its argument. If FLAGS is non-zero, we are printing for portable
991 re-input and should single-quote filenames appropriately. */
992char *
993printable_filename (fn, flags)
994 char *fn;
995 int flags;
996{
997 char *newf;
998
999 if (ansic_shouldquote (fn))
1000 newf = ansic_quote (fn, 0, NULL);
1001 else if (flags && sh_contains_shell_metas (fn))
1002 newf = sh_single_quote (fn);
1003 else
1004 newf = fn;
1005
1006 return newf;
1007}
1008
ccc6cda3
JA
1009/* Given a string containing units of information separated by colons,
1010 return the next one pointed to by (P_INDEX), or NULL if there are no more.
1011 Advance (P_INDEX) to the character after the colon. */
1012char *
1013extract_colon_unit (string, p_index)
1014 char *string;
1015 int *p_index;
726f6388 1016{
ccc6cda3
JA
1017 int i, start, len;
1018 char *value;
726f6388 1019
ccc6cda3
JA
1020 if (string == 0)
1021 return (string);
726f6388 1022
ccc6cda3
JA
1023 len = strlen (string);
1024 if (*p_index >= len)
1025 return ((char *)NULL);
726f6388 1026
ccc6cda3 1027 i = *p_index;
726f6388 1028
ccc6cda3
JA
1029 /* Each call to this routine leaves the index pointing at a colon if
1030 there is more to the path. If I is > 0, then increment past the
1031 `:'. If I is 0, then the path has a leading colon. Trailing colons
1032 are handled OK by the `else' part of the if statement; an empty
1033 string is returned in that case. */
1034 if (i && string[i] == ':')
1035 i++;
1036
1037 for (start = i; string[i] && string[i] != ':'; i++)
1038 ;
1039
1040 *p_index = i;
1041
1042 if (i == start)
1043 {
1044 if (string[i])
1045 (*p_index)++;
1046 /* Return "" in the case of a trailing `:'. */
f73dda09 1047 value = (char *)xmalloc (1);
ccc6cda3
JA
1048 value[0] = '\0';
1049 }
1050 else
bb70624e 1051 value = substring (string, start, i);
ccc6cda3
JA
1052
1053 return (value);
726f6388 1054}
726f6388
JA
1055
1056/* **************************************************************** */
1057/* */
1058/* Tilde Initialization and Expansion */
1059/* */
1060/* **************************************************************** */
1061
cce855bc 1062#if defined (PUSHD_AND_POPD)
8868edaf 1063extern char *get_dirstack_from_string PARAMS((char *));
cce855bc
JA
1064#endif
1065
f73dda09 1066static char **bash_tilde_prefixes;
95732b49 1067static char **bash_tilde_prefixes2;
f73dda09 1068static char **bash_tilde_suffixes;
95732b49 1069static char **bash_tilde_suffixes2;
f73dda09 1070
726f6388
JA
1071/* If tilde_expand hasn't been able to expand the text, perhaps it
1072 is a special shell expansion. This function is installed as the
cce855bc
JA
1073 tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+.
1074 If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the
1075 directory stack. */
726f6388 1076static char *
d166f048 1077bash_special_tilde_expansions (text)
726f6388
JA
1078 char *text;
1079{
ccc6cda3 1080 char *result;
726f6388 1081
ccc6cda3 1082 result = (char *)NULL;
cce855bc
JA
1083
1084 if (text[0] == '+' && text[1] == '\0')
1085 result = get_string_value ("PWD");
1086 else if (text[0] == '-' && text[1] == '\0')
1087 result = get_string_value ("OLDPWD");
1088#if defined (PUSHD_AND_POPD)
f73dda09 1089 else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
cce855bc
JA
1090 result = get_dirstack_from_string (text);
1091#endif
726f6388 1092
ccc6cda3 1093 return (result ? savestring (result) : (char *)NULL);
726f6388
JA
1094}
1095
1096/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
1097 well as handling special tilde prefixes; `:~" and `=~' are indications
1098 that we should do tilde expansion. */
1099void
1100tilde_initialize ()
1101{
1102 static int times_called = 0;
1103
d166f048 1104 /* Tell the tilde expander that we want a crack first. */
f73dda09 1105 tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
726f6388
JA
1106
1107 /* Tell the tilde expander about special strings which start a tilde
1108 expansion, and the special strings that end one. Only do this once.
1109 tilde_initialize () is called from within bashline_reinitialize (). */
cce855bc 1110 if (times_called++ == 0)
726f6388 1111 {
7117c2d2 1112 bash_tilde_prefixes = strvec_create (3);
f73dda09
JA
1113 bash_tilde_prefixes[0] = "=~";
1114 bash_tilde_prefixes[1] = ":~";
1115 bash_tilde_prefixes[2] = (char *)NULL;
1116
95732b49
JA
1117 bash_tilde_prefixes2 = strvec_create (2);
1118 bash_tilde_prefixes2[0] = ":~";
1119 bash_tilde_prefixes2[1] = (char *)NULL;
1120
f73dda09
JA
1121 tilde_additional_prefixes = bash_tilde_prefixes;
1122
7117c2d2 1123 bash_tilde_suffixes = strvec_create (3);
f73dda09
JA
1124 bash_tilde_suffixes[0] = ":";
1125 bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */
1126 bash_tilde_suffixes[2] = (char *)NULL;
1127
1128 tilde_additional_suffixes = bash_tilde_suffixes;
95732b49
JA
1129
1130 bash_tilde_suffixes2 = strvec_create (2);
1131 bash_tilde_suffixes2[0] = ":";
1132 bash_tilde_suffixes2[1] = (char *)NULL;
726f6388 1133 }
726f6388
JA
1134}
1135
f73dda09
JA
1136/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character
1137 at the beginning of the word, followed by all of the characters preceding
1138 the first unquoted slash in the word, or all the characters in the word
1139 if there is no slash...If none of the characters in the tilde-prefix are
1140 quoted, the characters in the tilde-prefix following the tilde shell be
1141 treated as a possible login name. */
1142
1143#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':')
1144
1145static int
1146unquoted_tilde_word (s)
1147 const char *s;
1148{
1149 const char *r;
1150
1151 for (r = s; TILDE_END(*r) == 0; r++)
1152 {
1153 switch (*r)
1154 {
1155 case '\\':
1156 case '\'':
1157 case '"':
1158 return 0;
1159 }
1160 }
1161 return 1;
1162}
1163
95732b49
JA
1164/* Find the end of the tilde-prefix starting at S, and return the tilde
1165 prefix in newly-allocated memory. Return the length of the string in
1166 *LENP. FLAGS tells whether or not we're in an assignment context --
1167 if so, `:' delimits the end of the tilde prefix as well. */
1168char *
1169bash_tilde_find_word (s, flags, lenp)
1170 const char *s;
1171 int flags, *lenp;
1172{
1173 const char *r;
1174 char *ret;
1175 int l;
1176
1177 for (r = s; *r && *r != '/'; r++)
1178 {
1179 /* Short-circuit immediately if we see a quote character. Even though
1180 POSIX says that `the first unquoted slash' (or `:') terminates the
1181 tilde-prefix, in practice, any quoted portion of the tilde prefix
1182 will cause it to not be expanded. */
1183 if (*r == '\\' || *r == '\'' || *r == '"')
1184 {
1185 ret = savestring (s);
1186 if (lenp)
1187 *lenp = 0;
1188 return ret;
1189 }
1190 else if (flags && *r == ':')
1191 break;
1192 }
1193 l = r - s;
1194 ret = xmalloc (l + 1);
1195 strncpy (ret, s, l);
1196 ret[l] = '\0';
1197 if (lenp)
1198 *lenp = l;
1199 return ret;
1200}
1201
7117c2d2
JA
1202/* Tilde-expand S by running it through the tilde expansion library.
1203 ASSIGN_P is 1 if this is a variable assignment, so the alternate
95732b49
JA
1204 tilde prefixes should be enabled (`=~' and `:~', see above). If
1205 ASSIGN_P is 2, we are expanding the rhs of an assignment statement,
1206 so `=~' is not valid. */
ccc6cda3 1207char *
7117c2d2 1208bash_tilde_expand (s, assign_p)
f73dda09 1209 const char *s;
7117c2d2 1210 int assign_p;
726f6388 1211{
8868edaf 1212 int r;
ccc6cda3 1213 char *ret;
726f6388 1214
95732b49
JA
1215 tilde_additional_prefixes = assign_p == 0 ? (char **)0
1216 : (assign_p == 2 ? bash_tilde_prefixes2 : bash_tilde_prefixes);
1217 if (assign_p == 2)
1218 tilde_additional_suffixes = bash_tilde_suffixes2;
1219
f73dda09
JA
1220 r = (*s == '~') ? unquoted_tilde_word (s) : 1;
1221 ret = r ? tilde_expand (s) : savestring (s);
ac50fbac 1222
ac50fbac
CR
1223 QUIT;
1224
ccc6cda3 1225 return (ret);
726f6388 1226}
d166f048
JA
1227
1228/* **************************************************************** */
1229/* */
1230/* Functions to manipulate and search the group list */
1231/* */
1232/* **************************************************************** */
1233
1234static int ngroups, maxgroups;
1235
1236/* The set of groups that this user is a member of. */
1237static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
1238
1239#if !defined (NOGROUP)
1240# define NOGROUP (gid_t) -1
1241#endif
1242
d166f048
JA
1243static void
1244initialize_group_array ()
1245{
1246 register int i;
1247
1248 if (maxgroups == 0)
1249 maxgroups = getmaxgroups ();
1250
1251 ngroups = 0;
1252 group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
1253
1254#if defined (HAVE_GETGROUPS)
1255 ngroups = getgroups (maxgroups, group_array);
1256#endif
1257
1258 /* If getgroups returns nothing, or the OS does not support getgroups(),
1259 make sure the groups array includes at least the current gid. */
1260 if (ngroups == 0)
1261 {
1262 group_array[0] = current_user.gid;
1263 ngroups = 1;
1264 }
1265
1266 /* If the primary group is not in the groups array, add it as group_array[0]
1267 and shuffle everything else up 1, if there's room. */
1268 for (i = 0; i < ngroups; i++)
1269 if (current_user.gid == (gid_t)group_array[i])
1270 break;
1271 if (i == ngroups && ngroups < maxgroups)
1272 {
1273 for (i = ngroups; i > 0; i--)
28ef6c31 1274 group_array[i] = group_array[i - 1];
d166f048
JA
1275 group_array[0] = current_user.gid;
1276 ngroups++;
1277 }
cce855bc
JA
1278
1279 /* If the primary group is not group_array[0], swap group_array[0] and
1280 whatever the current group is. The vast majority of systems should
1281 not need this; a notable exception is Linux. */
1282 if (group_array[0] != current_user.gid)
1283 {
1284 for (i = 0; i < ngroups; i++)
28ef6c31
JA
1285 if (group_array[i] == current_user.gid)
1286 break;
cce855bc
JA
1287 if (i < ngroups)
1288 {
1289 group_array[i] = group_array[0];
1290 group_array[0] = current_user.gid;
1291 }
1292 }
d166f048
JA
1293}
1294
1295/* Return non-zero if GID is one that we have in our groups list. */
1296int
cce855bc
JA
1297#if defined (__STDC__) || defined ( _MINIX)
1298group_member (gid_t gid)
1299#else
d166f048
JA
1300group_member (gid)
1301 gid_t gid;
cce855bc 1302#endif /* !__STDC__ && !_MINIX */
d166f048
JA
1303{
1304#if defined (HAVE_GETGROUPS)
1305 register int i;
1306#endif
1307
1308 /* Short-circuit if possible, maybe saving a call to getgroups(). */
1309 if (gid == current_user.gid || gid == current_user.egid)
1310 return (1);
1311
1312#if defined (HAVE_GETGROUPS)
1313 if (ngroups == 0)
1314 initialize_group_array ();
1315
1316 /* In case of error, the user loses. */
1317 if (ngroups <= 0)
1318 return (0);
1319
1320 /* Search through the list looking for GID. */
1321 for (i = 0; i < ngroups; i++)
1322 if (gid == (gid_t)group_array[i])
1323 return (1);
1324#endif
1325
1326 return (0);
1327}
1328
1329char **
1330get_group_list (ngp)
1331 int *ngp;
1332{
1333 static char **group_vector = (char **)NULL;
1334 register int i;
d166f048
JA
1335
1336 if (group_vector)
1337 {
1338 if (ngp)
1339 *ngp = ngroups;
1340 return group_vector;
1341 }
1342
1343 if (ngroups == 0)
1344 initialize_group_array ();
1345
1346 if (ngroups <= 0)
1347 {
1348 if (ngp)
1349 *ngp = 0;
1350 return (char **)NULL;
1351 }
1352
7117c2d2 1353 group_vector = strvec_create (ngroups);
d166f048 1354 for (i = 0; i < ngroups; i++)
7117c2d2 1355 group_vector[i] = itos (group_array[i]);
b72432fd 1356
d166f048
JA
1357 if (ngp)
1358 *ngp = ngroups;
1359 return group_vector;
1360}
b72432fd
JA
1361
1362int *
1363get_group_array (ngp)
1364 int *ngp;
1365{
1366 int i;
1367 static int *group_iarray = (int *)NULL;
1368
1369 if (group_iarray)
1370 {
1371 if (ngp)
1372 *ngp = ngroups;
1373 return (group_iarray);
1374 }
1375
1376 if (ngroups == 0)
1377 initialize_group_array ();
1378
1379 if (ngroups <= 0)
1380 {
1381 if (ngp)
1382 *ngp = 0;
1383 return (int *)NULL;
1384 }
1385
1386 group_iarray = (int *)xmalloc (ngroups * sizeof (int));
1387 for (i = 0; i < ngroups; i++)
1388 group_iarray[i] = (int)group_array[i];
1389
1390 if (ngp)
1391 *ngp = ngroups;
1392 return group_iarray;
1393}
a0c0a00f
CR
1394
1395/* **************************************************************** */
1396/* */
1397/* Miscellaneous functions */
1398/* */
1399/* **************************************************************** */
1400
1401/* Return a value for PATH that is guaranteed to find all of the standard
1402 utilities. This uses Posix.2 configuration variables, if present. It
1403 uses a value defined in config.h as a last resort. */
1404char *
1405conf_standard_path ()
1406{
1407#if defined (_CS_PATH) && defined (HAVE_CONFSTR)
1408 char *p;
1409 size_t len;
1410
1411 len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0);
1412 if (len > 0)
1413 {
1414 p = (char *)xmalloc (len + 2);
1415 *p = '\0';
1416 confstr (_CS_PATH, p, len);
1417 return (p);
1418 }
1419 else
1420 return (savestring (STANDARD_UTILS_PATH));
1421#else /* !_CS_PATH || !HAVE_CONFSTR */
1422# if defined (CS_PATH)
1423 return (savestring (CS_PATH));
1424# else
1425 return (savestring (STANDARD_UTILS_PATH));
1426# endif /* !CS_PATH */
1427#endif /* !_CS_PATH || !HAVE_CONFSTR */
1428}
d233b485
CR
1429
1430int
1431default_columns ()
1432{
1433 char *v;
1434 int c;
1435
1436 c = -1;
1437 v = get_string_value ("COLUMNS");
1438 if (v && *v)
1439 {
1440 c = atoi (v);
1441 if (c > 0)
1442 return c;
1443 }
1444
1445 if (check_window_size)
1446 get_new_window_size (0, (int *)0, &c);
1447
1448 return (c > 0 ? c : 80);
1449}
1450
1451