Automatic date update in version.in
[deliverable/binutils-gdb.git] / binutils / bucomm.c
CommitLineData
252b5132 1/* bucomm.c -- Bin Utils COMmon code.
250d07de 2 Copyright (C) 1991-2021 Free Software Foundation, Inc.
252b5132
RH
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
32866df7 8 the Free Software Foundation; either version 3 of the License, or
252b5132
RH
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
b43b5d5f
NC
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19 02110-1301, USA. */
252b5132
RH
20\f
21/* We might put this in a library someday so it could be dynamically
22 loaded, but for now it's not necessary. */
23
3db64b00 24#include "sysdep.h"
252b5132
RH
25#include "bfd.h"
26#include "libiberty.h"
5af11cab 27#include "filenames.h"
87b9f255 28#include <time.h>
77f762d6 29#include <assert.h>
3db64b00 30#include "bucomm.h"
252b5132 31\f
06d86cf7 32/* Error reporting. */
252b5132
RH
33
34char *program_name;
35
36void
2da42df6 37bfd_nonfatal (const char *string)
252b5132 38{
a8c62f1c 39 const char *errmsg;
a68aa5d3 40 enum bfd_error err = bfd_get_error ();
252b5132 41
a68aa5d3
NC
42 if (err == bfd_error_no_error)
43 errmsg = _("cause of error unknown");
44 else
45 errmsg = bfd_errmsg (err);
8e085dd2 46 fflush (stdout);
252b5132
RH
47 if (string)
48 fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
49 else
50 fprintf (stderr, "%s: %s\n", program_name, errmsg);
51}
52
2db6cde7
NS
53/* Issue a non fatal error message. FILENAME, or if NULL then BFD,
54 are used to indicate the problematic file. SECTION, if non NULL,
55 is used to provide a section name. If FORMAT is non-null, then it
56 is used to print additional information via vfprintf. Finally the
57 bfd error message is printed. In summary, error messages are of
58 one of the following forms:
59
df56ecde
AM
60 PROGRAM: file: bfd-error-message
61 PROGRAM: file[section]: bfd-error-message
62 PROGRAM: file: printf-message: bfd-error-message
63 PROGRAM: file[section]: printf-message: bfd-error-message. */
2db6cde7
NS
64
65void
66bfd_nonfatal_message (const char *filename,
91d6fa6a
NC
67 const bfd *abfd,
68 const asection *section,
2db6cde7
NS
69 const char *format, ...)
70{
a8c62f1c
AM
71 const char *errmsg;
72 const char *section_name;
2db6cde7 73 va_list args;
a68aa5d3 74 enum bfd_error err = bfd_get_error ();
2db6cde7 75
a68aa5d3
NC
76 if (err == bfd_error_no_error)
77 errmsg = _("cause of error unknown");
78 else
79 errmsg = bfd_errmsg (err);
8e085dd2 80 fflush (stdout);
a8c62f1c 81 section_name = NULL;
2db6cde7
NS
82 va_start (args, format);
83 fprintf (stderr, "%s", program_name);
3aade688 84
91d6fa6a 85 if (abfd)
2db6cde7
NS
86 {
87 if (!filename)
91d6fa6a 88 filename = bfd_get_archive_filename (abfd);
2db6cde7 89 if (section)
fd361982 90 section_name = bfd_section_name (section);
2db6cde7
NS
91 }
92 if (section_name)
df56ecde 93 fprintf (stderr, ": %s[%s]", filename, section_name);
2db6cde7 94 else
df56ecde 95 fprintf (stderr, ": %s", filename);
2db6cde7
NS
96
97 if (format)
98 {
99 fprintf (stderr, ": ");
100 vfprintf (stderr, format, args);
101 }
102 fprintf (stderr, ": %s\n", errmsg);
103 va_end (args);
104}
105
252b5132 106void
2da42df6 107bfd_fatal (const char *string)
252b5132
RH
108{
109 bfd_nonfatal (string);
110 xexit (1);
111}
112
cba12006 113void
2da42df6 114report (const char * format, va_list args)
252b5132 115{
a8c62f1c 116 fflush (stdout);
252b5132
RH
117 fprintf (stderr, "%s: ", program_name);
118 vfprintf (stderr, format, args);
119 putc ('\n', stderr);
120}
121
252b5132 122void
1651e569 123fatal (const char *format, ...)
252b5132 124{
1651e569
TT
125 va_list args;
126
127 va_start (args, format);
252b5132 128
252b5132 129 report (format, args);
1651e569 130 va_end (args);
252b5132
RH
131 xexit (1);
132}
133
134void
1651e569 135non_fatal (const char *format, ...)
252b5132 136{
1651e569
TT
137 va_list args;
138
139 va_start (args, format);
252b5132 140
252b5132 141 report (format, args);
1651e569 142 va_end (args);
252b5132 143}
252b5132
RH
144
145/* Set the default BFD target based on the configured target. Doing
146 this permits the binutils to be configured for a particular target,
147 and linked against a shared BFD library which was configured for a
148 different target. */
149
150void
2da42df6 151set_default_bfd_target (void)
252b5132
RH
152{
153 /* The macro TARGET is defined by Makefile. */
154 const char *target = TARGET;
155
156 if (! bfd_set_default_target (target))
157 fatal (_("can't set BFD default target to `%s': %s"),
158 target, bfd_errmsg (bfd_get_error ()));
159}
160
b34976b6 161/* After a FALSE return from bfd_check_format_matches with
252b5132
RH
162 bfd_get_error () == bfd_error_file_ambiguously_recognized, print
163 the possible matching targets. */
164
165void
2da42df6 166list_matching_formats (char **p)
252b5132 167{
a8c62f1c 168 fflush (stdout);
252b5132
RH
169 fprintf (stderr, _("%s: Matching formats:"), program_name);
170 while (*p)
171 fprintf (stderr, " %s", *p++);
172 fputc ('\n', stderr);
173}
174
175/* List the supported targets. */
176
177void
2da42df6 178list_supported_targets (const char *name, FILE *f)
252b5132 179{
252b5132 180 int t;
a8c62f1c 181 const char **targ_names;
252b5132
RH
182
183 if (name == NULL)
184 fprintf (f, _("Supported targets:"));
185 else
186 fprintf (f, _("%s: supported targets:"), name);
48417c1a 187
a8c62f1c 188 targ_names = bfd_target_list ();
48417c1a
AM
189 for (t = 0; targ_names[t] != NULL; t++)
190 fprintf (f, " %s", targ_names[t]);
252b5132 191 fprintf (f, "\n");
48417c1a 192 free (targ_names);
252b5132 193}
2f83960e
AM
194
195/* List the supported architectures. */
196
197void
2da42df6 198list_supported_architectures (const char *name, FILE *f)
2f83960e 199{
d25576aa
NC
200 const char ** arch;
201 const char ** arches;
2f83960e
AM
202
203 if (name == NULL)
204 fprintf (f, _("Supported architectures:"));
205 else
206 fprintf (f, _("%s: supported architectures:"), name);
207
d25576aa 208 for (arch = arches = bfd_arch_list (); *arch; arch++)
2f83960e
AM
209 fprintf (f, " %s", *arch);
210 fprintf (f, "\n");
d25576aa 211 free (arches);
2f83960e 212}
252b5132 213\f
06d86cf7 214static const char *
2da42df6 215endian_string (enum bfd_endian endian)
06d86cf7
NC
216{
217 switch (endian)
218 {
9cf03b7e
NC
219 case BFD_ENDIAN_BIG: return _("big endian");
220 case BFD_ENDIAN_LITTLE: return _("little endian");
221 default: return _("endianness unknown");
06d86cf7
NC
222 }
223}
224
aac502f7
AM
225/* Data passed to do_display_target and other target iterators. */
226
227struct display_target {
228 /* Temp file. */
229 char *filename;
230 /* Return status. */
231 int error;
232 /* Number of targets. */
233 int count;
234 /* Size of info in bytes. */
235 size_t alloc;
236 /* Per-target info. */
237 struct {
238 /* Target name. */
239 const char *name;
240 /* Non-zero if target/arch combination supported. */
241 unsigned char arch[bfd_arch_last - bfd_arch_obscure - 1];
242 } *info;
243};
244
06d86cf7 245/* List the targets that BFD is configured to support, each followed
aac502f7
AM
246 by its endianness and the architectures it supports. Also build
247 info about target/archs. */
06d86cf7
NC
248
249static int
aac502f7 250do_display_target (const bfd_target *targ, void *data)
06d86cf7 251{
aac502f7
AM
252 struct display_target *param = (struct display_target *) data;
253 bfd *abfd;
254 size_t amt;
06d86cf7 255
aac502f7
AM
256 param->count += 1;
257 amt = param->count * sizeof (*param->info);
258 if (param->alloc < amt)
06d86cf7 259 {
aac502f7
AM
260 size_t size = ((param->count < 64 ? 64 : param->count)
261 * sizeof (*param->info) * 2);
262 param->info = xrealloc (param->info, size);
263 memset ((char *) param->info + param->alloc, 0, size - param->alloc);
264 param->alloc = size;
265 }
266 param->info[param->count - 1].name = targ->name;
06d86cf7 267
aac502f7
AM
268 printf (_("%s\n (header %s, data %s)\n"), targ->name,
269 endian_string (targ->header_byteorder),
270 endian_string (targ->byteorder));
06d86cf7 271
aac502f7
AM
272 abfd = bfd_openw (param->filename, targ->name);
273 if (abfd == NULL)
274 {
275 bfd_nonfatal (param->filename);
276 param->error = 1;
277 }
278 else if (!bfd_set_format (abfd, bfd_object))
279 {
280 if (bfd_get_error () != bfd_error_invalid_operation)
06d86cf7 281 {
aac502f7
AM
282 bfd_nonfatal (targ->name);
283 param->error = 1;
06d86cf7 284 }
aac502f7
AM
285 }
286 else
287 {
288 enum bfd_architecture a;
06d86cf7 289
91610c0c 290 for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
aac502f7
AM
291 if (bfd_set_arch_mach (abfd, a, 0))
292 {
293 printf (" %s\n", bfd_printable_arch_mach (a, 0));
294 param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1;
295 }
06d86cf7 296 }
aac502f7
AM
297 if (abfd != NULL)
298 bfd_close_all_done (abfd);
06d86cf7 299
aac502f7 300 return param->error;
06d86cf7
NC
301}
302
aac502f7
AM
303static void
304display_target_list (struct display_target *arg)
305{
306 arg->filename = make_temp_file (NULL);
307 arg->error = 0;
308 arg->count = 0;
309 arg->alloc = 0;
310 arg->info = NULL;
311
312 bfd_iterate_over_targets (do_display_target, arg);
313
314 unlink (arg->filename);
315 free (arg->filename);
316}
317
318/* Calculate how many targets we can print across the page. */
06d86cf7
NC
319
320static int
aac502f7 321do_info_size (int targ, int width, const struct display_target *arg)
06d86cf7 322{
aac502f7
AM
323 while (targ < arg->count)
324 {
325 width -= strlen (arg->info[targ].name) + 1;
326 if (width < 0)
327 return targ;
328 ++targ;
329 }
330 return targ;
331}
332
333/* Print header of target names. */
06d86cf7 334
aac502f7
AM
335static void
336do_info_header (int targ, int stop_targ, const struct display_target *arg)
337{
338 while (targ != stop_targ)
339 printf ("%s ", arg->info[targ++].name);
340}
341
342/* Print a table row. */
343
344static void
345do_info_row (int targ, int stop_targ, enum bfd_architecture a,
346 const struct display_target *arg)
347{
348 while (targ != stop_targ)
349 {
350 if (arg->info[targ].arch[a - bfd_arch_obscure - 1])
351 fputs (arg->info[targ].name, stdout);
352 else
353 {
354 int l = strlen (arg->info[targ].name);
355 while (l--)
356 putchar ('-');
357 }
358 ++targ;
359 if (targ != stop_targ)
360 putchar (' ');
361 }
06d86cf7
NC
362}
363
364/* Print tables of all the target-architecture combinations that
365 BFD has been configured to support. */
366
aac502f7
AM
367static void
368display_target_tables (const struct display_target *arg)
06d86cf7 369{
aac502f7
AM
370 const char *columns;
371 int width, start_targ, stop_targ;
372 enum bfd_architecture arch;
373 int longest_arch = 0;
374
375 for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
06d86cf7 376 {
aac502f7
AM
377 const char *s = bfd_printable_arch_mach (arch, 0);
378 int len = strlen (s);
379 if (len > longest_arch)
380 longest_arch = len;
381 }
06d86cf7 382
aac502f7
AM
383 width = 0;
384 columns = getenv ("COLUMNS");
385 if (columns != NULL)
386 width = atoi (columns);
387 if (width == 0)
388 width = 80;
389
390 for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ)
391 {
392 stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg);
393
394 printf ("\n%*s", longest_arch + 1, " ");
395 do_info_header (start_targ, stop_targ, arg);
396 putchar ('\n');
06d86cf7 397
aac502f7
AM
398 for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
399 {
400 if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0)
401 {
402 printf ("%*s ", longest_arch,
403 bfd_printable_arch_mach (arch, 0));
404
405 do_info_row (start_targ, stop_targ, arch, arg);
406 putchar ('\n');
407 }
06d86cf7 408 }
06d86cf7 409 }
06d86cf7
NC
410}
411
412int
2da42df6 413display_info (void)
06d86cf7 414{
aac502f7
AM
415 struct display_target arg;
416
06d86cf7 417 printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
aac502f7
AM
418
419 display_target_list (&arg);
420 if (!arg.error)
421 display_target_tables (&arg);
422
423 return arg.error;
06d86cf7
NC
424}
425\f
252b5132
RH
426/* Display the archive header for an element as if it were an ls -l listing:
427
428 Mode User\tGroup\tSize\tDate Name */
429
430void
015dc7e1 431print_arelt_descr (FILE *file, bfd *abfd, bool verbose, bool offsets)
252b5132
RH
432{
433 struct stat buf;
434
435 if (verbose)
436 {
437 if (bfd_stat_arch_elt (abfd, &buf) == 0)
438 {
439 char modebuf[11];
440 char timebuf[40];
441 time_t when = buf.st_mtime;
b1f88ebe 442 const char *ctime_result = (const char *) ctime (&when);
34debcd1 443 bfd_size_type size;
252b5132 444
0593bd3a
NC
445 /* PR binutils/17605: Check for corrupt time values. */
446 if (ctime_result == NULL)
447 sprintf (timebuf, _("<time data corrupt>"));
448 else
449 /* POSIX format: skip weekday and seconds from ctime output. */
450 sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
252b5132
RH
451
452 mode_string (buf.st_mode, modebuf);
453 modebuf[10] = '\0';
34debcd1 454 size = buf.st_size;
252b5132 455 /* POSIX 1003.2/D11 says to skip first character (entry type). */
34debcd1 456 fprintf (file, "%s %ld/%ld %6" BFD_VMA_FMT "u %s ", modebuf + 1,
252b5132 457 (long) buf.st_uid, (long) buf.st_gid,
34debcd1 458 size, timebuf);
252b5132
RH
459 }
460 }
461
1869e86f
AB
462 fprintf (file, "%s", bfd_get_filename (abfd));
463
464 if (offsets)
465 {
466 if (bfd_is_thin_archive (abfd) && abfd->proxy_origin)
467 fprintf (file, " 0x%lx", (unsigned long) abfd->proxy_origin);
468 else if (!bfd_is_thin_archive (abfd) && abfd->origin)
469 fprintf (file, " 0x%lx", (unsigned long) abfd->origin);
470 }
471
472 fprintf (file, "\n");
252b5132
RH
473}
474
485be063
AM
475/* Return a path for a new temporary file in the same directory
476 as file PATH. */
252b5132 477
485be063
AM
478static char *
479template_in_dir (const char *path)
252b5132 480{
485be063 481#define template "stXXXXXX"
2946671e 482 const char *slash = strrchr (path, '/');
252b5132 483 char *tmpname;
485be063 484 size_t len;
252b5132 485
5af11cab
AM
486#ifdef HAVE_DOS_BASED_FILE_SYSTEM
487 {
488 /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
485be063 489 char *bslash = strrchr (path, '\\');
f9c026a8 490
2ab47eed 491 if (slash == NULL || (bslash != NULL && bslash > slash))
5af11cab 492 slash = bslash;
485be063 493 if (slash == NULL && path[0] != '\0' && path[1] == ':')
2946671e 494 slash = path + 1;
5af11cab 495 }
252b5132
RH
496#endif
497
498 if (slash != (char *) NULL)
499 {
485be063 500 len = slash - path;
3f5e193b 501 tmpname = (char *) xmalloc (len + sizeof (template) + 2);
485be063 502 memcpy (tmpname, path, len);
252b5132 503
5af11cab
AM
504#ifdef HAVE_DOS_BASED_FILE_SYSTEM
505 /* If tmpname is "X:", appending a slash will make it a root
506 directory on drive X, which is NOT the same as the current
507 directory on drive X. */
485be063
AM
508 if (len == 2 && tmpname[1] == ':')
509 tmpname[len++] = '.';
5af11cab 510#endif
485be063 511 tmpname[len++] = '/';
252b5132
RH
512 }
513 else
514 {
3f5e193b 515 tmpname = (char *) xmalloc (sizeof (template));
485be063 516 len = 0;
f9c026a8 517 }
485be063
AM
518
519 memcpy (tmpname + len, template, sizeof (template));
520 return tmpname;
521#undef template
522}
523
524/* Return the name of a created temporary file in the same directory
525 as FILENAME. */
526
527char *
365f5fb6 528make_tempname (const char *filename, int *ofd)
485be063
AM
529{
530 char *tmpname = template_in_dir (filename);
531 int fd;
532
533#ifdef HAVE_MKSTEMP
534 fd = mkstemp (tmpname);
535#else
536 tmpname = mktemp (tmpname);
537 if (tmpname == NULL)
f9c026a8 538 return NULL;
485be063 539 fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600);
f9c026a8 540#endif
485be063 541 if (fd == -1)
c48d800e
NC
542 {
543 free (tmpname);
544 return NULL;
545 }
365f5fb6 546 *ofd = fd;
f9c026a8
NC
547 return tmpname;
548}
549
485be063
AM
550/* Return the name of a created temporary directory inside the
551 directory containing FILENAME. */
f9c026a8
NC
552
553char *
1ff5d5c4 554make_tempdir (const char *filename)
f9c026a8 555{
485be063 556 char *tmpname = template_in_dir (filename);
f9c026a8 557
485be063
AM
558#ifdef HAVE_MKDTEMP
559 return mkdtemp (tmpname);
560#else
561 tmpname = mktemp (tmpname);
562 if (tmpname == NULL)
563 return NULL;
564#if defined (_WIN32) && !defined (__CYGWIN32__)
565 if (mkdir (tmpname) != 0)
566 return NULL;
567#else
568 if (mkdir (tmpname, 0700) != 0)
569 return NULL;
f9c026a8 570#endif
252b5132 571 return tmpname;
485be063 572#endif
252b5132
RH
573}
574
575/* Parse a string into a VMA, with a fatal error if it can't be
576 parsed. */
577
578bfd_vma
2da42df6 579parse_vma (const char *s, const char *arg)
252b5132
RH
580{
581 bfd_vma ret;
582 const char *end;
583
584 ret = bfd_scan_vma (s, &end, 0);
f462a9ea 585
252b5132
RH
586 if (*end != '\0')
587 fatal (_("%s: bad number: %s"), arg, s);
588
589 return ret;
590}
f24ddbdd
NC
591
592/* Returns the size of the named file. If the file does not
593 exist, or if it is not a real file, then a suitable non-fatal
a3029abd 594 error message is printed and (off_t) -1 is returned. */
f24ddbdd
NC
595
596off_t
597get_file_size (const char * file_name)
598{
599 struct stat statbuf;
3aade688 600
740a4630
NC
601 if (file_name == NULL)
602 return (off_t) -1;
603
f24ddbdd
NC
604 if (stat (file_name, &statbuf) < 0)
605 {
606 if (errno == ENOENT)
607 non_fatal (_("'%s': No such file"), file_name);
608 else
609 non_fatal (_("Warning: could not locate '%s'. reason: %s"),
610 file_name, strerror (errno));
3aade688 611 }
0602cdad
NC
612 else if (S_ISDIR (statbuf.st_mode))
613 non_fatal (_("Warning: '%s' is a directory"), file_name);
f24ddbdd
NC
614 else if (! S_ISREG (statbuf.st_mode))
615 non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
9849fbfc
NC
616 else if (statbuf.st_size < 0)
617 non_fatal (_("Warning: '%s' has negative size, probably it is too large"),
618 file_name);
a7ad3cb1
EZ
619#if defined (_WIN32) && !defined (__CYGWIN__)
620 else if (statbuf.st_size == 0)
621 {
887854ba
EZ
622 /* MS-Windows 'stat' reports the null device as a regular file;
623 fix that. */
a7ad3cb1
EZ
624 int fd = open (file_name, O_RDONLY | O_BINARY);
625 if (isatty (fd))
626 {
627 close (fd);
628 non_fatal (_("Warning: '%s' is not an ordinary file"),
629 /* libtool wants to see /dev/null in the output. */
630 strcasecmp (file_name, "nul") ? file_name : "/dev/null");
631 }
632 }
633#endif
f24ddbdd
NC
634 else
635 return statbuf.st_size;
636
52a476ee 637 return (off_t) -1;
f24ddbdd 638}
77f762d6
L
639
640/* Return the filename in a static buffer. */
641
642const char *
8d8e0703 643bfd_get_archive_filename (const bfd *abfd)
77f762d6
L
644{
645 static size_t curr = 0;
646 static char *buf;
647 size_t needed;
648
649 assert (abfd != NULL);
3aade688 650
b0cffb47
AM
651 if (abfd->my_archive == NULL
652 || bfd_is_thin_archive (abfd->my_archive))
77f762d6
L
653 return bfd_get_filename (abfd);
654
655 needed = (strlen (bfd_get_filename (abfd->my_archive))
656 + strlen (bfd_get_filename (abfd)) + 3);
657 if (needed > curr)
658 {
659 if (curr)
660 free (buf);
661 curr = needed + (needed >> 1);
76e7a751 662 buf = (char *) xmalloc (curr);
77f762d6
L
663 }
664 sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
665 bfd_get_filename (abfd));
666 return buf;
667}
dd9b91de
NC
668
669/* Returns TRUE iff PATHNAME, a filename of an archive member,
670 is valid for writing. For security reasons absolute paths
671 and paths containing /../ are not allowed. See PR 17533. */
672
015dc7e1 673bool
dd9b91de
NC
674is_valid_archive_path (char const * pathname)
675{
676 const char * n = pathname;
677
678 if (IS_ABSOLUTE_PATH (n))
015dc7e1 679 return false;
dd9b91de
NC
680
681 while (*n)
682 {
683 if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n)))
015dc7e1 684 return false;
dd9b91de
NC
685
686 while (*n && ! IS_DIR_SEPARATOR (*n))
687 n++;
688 while (IS_DIR_SEPARATOR (*n))
689 n++;
690 }
691
015dc7e1 692 return true;
dd9b91de 693}
This page took 1.081506 seconds and 4 git commands to generate.