Fix for complex situations where directories are declared as prerequisites.
[make.git] / arscan.c
blobfc003e99537b0ae89809d9176299cc24f3b4d872
1 /* Library function for scanning an archive file.
2 Copyright (C) 1987,89,91,92,93,94,95,97 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA. */
19 #include "make.h"
21 #ifdef HAVE_FCNTL_H
22 #include <fcntl.h>
23 #else
24 #include <sys/file.h>
25 #endif
27 #ifndef NO_ARCHIVES
29 #ifdef VMS
30 #include <lbrdef.h>
31 #include <mhddef.h>
32 #include <credef.h>
33 #include <descrip.h>
34 #include <ctype.h>
35 #if __DECC
36 #include <unixlib.h>
37 #include <lbr$routines.h>
38 #endif
40 static void *VMS_lib_idx;
42 static char *VMS_saved_memname;
44 static time_t VMS_member_date;
46 static long int (*VMS_function) ();
48 static int
49 VMS_get_member_info (module, rfa)
50 struct dsc$descriptor_s *module;
51 unsigned long *rfa;
53 int status, i;
54 long int fnval;
56 time_t val;
58 static struct dsc$descriptor_s bufdesc =
59 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
61 struct mhddef *mhd;
62 char filename[128];
64 bufdesc.dsc$a_pointer = filename;
65 bufdesc.dsc$w_length = sizeof (filename);
67 status = lbr$set_module (&VMS_lib_idx, rfa, &bufdesc,
68 &bufdesc.dsc$w_length, 0);
69 if (! (status & 1))
71 error (NILF, _("lbr$set_module failed to extract module info, status = %d"),
72 status);
74 lbr$close (&VMS_lib_idx);
76 return 0;
79 mhd = (struct mhddef *) filename;
81 #ifdef __DECC
82 /* John Fowler <jfowler@nyx.net> writes this is needed in his environment,
83 * but that decc$fix_time() isn't documented to work this way. Let me
84 * know if this causes problems in other VMS environments.
86 val = decc$fix_time (&mhd->mhd$l_datim) + timezone - daylight*3600;
87 #endif
89 for (i = 0; i < module->dsc$w_length; i++)
90 filename[i] = _tolower ((unsigned char)module->dsc$a_pointer[i]);
92 filename[i] = '\0';
94 VMS_member_date = (time_t) -1;
96 fnval =
97 (*VMS_function) (-1, filename, 0, 0, 0, 0, val, 0, 0, 0,
98 VMS_saved_memname);
100 if (fnval)
102 VMS_member_date = fnval;
103 return 0;
105 else
106 return 1;
109 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
111 Open the archive named ARCHIVE, find its members one by one,
112 and for each one call FUNCTION with the following arguments:
113 archive file descriptor for reading the data,
114 member name,
115 member name might be truncated flag,
116 member header position in file,
117 member data position in file,
118 member data size,
119 member date,
120 member uid,
121 member gid,
122 member protection mode,
123 ARG.
125 NOTE: on VMS systems, only name, date, and arg are meaningful!
127 The descriptor is poised to read the data of the member
128 when FUNCTION is called. It does not matter how much
129 data FUNCTION reads.
131 If FUNCTION returns nonzero, we immediately return
132 what FUNCTION returned.
134 Returns -1 if archive does not exist,
135 Returns -2 if archive has invalid format.
136 Returns 0 if have scanned successfully. */
138 long int
139 ar_scan (archive, function, arg)
140 char *archive;
141 long int (*function) ();
142 long int arg;
144 char *p;
146 static struct dsc$descriptor_s libdesc =
147 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
149 unsigned long func = LBR$C_READ;
150 unsigned long type = LBR$C_TYP_UNK;
151 unsigned long index = 1;
153 int status;
155 status = lbr$ini_control (&VMS_lib_idx, &func, &type, 0);
157 if (! (status & 1))
159 error (NILF, _("lbr$ini_control failed with status = %d"),status);
160 return -2;
163 libdesc.dsc$a_pointer = archive;
164 libdesc.dsc$w_length = strlen (archive);
166 status = lbr$open (&VMS_lib_idx, &libdesc, 0, 0, 0, 0, 0);
168 if (! (status & 1))
170 error (NILF, _("unable to open library `%s' to lookup member `%s'"),
171 archive, (char *)arg);
172 return -1;
175 VMS_saved_memname = (char *)arg;
177 /* For comparison, delete .obj from arg name. */
179 p = strrchr (VMS_saved_memname, '.');
180 if (p)
181 *p = '\0';
183 VMS_function = function;
185 VMS_member_date = (time_t) -1;
186 lbr$get_index (&VMS_lib_idx, &index, VMS_get_member_info, 0);
188 /* Undo the damage. */
189 if (p)
190 *p = '.';
192 lbr$close (&VMS_lib_idx);
194 return VMS_member_date > 0 ? VMS_member_date : 0;
197 #else /* !VMS */
199 /* SCO Unix's compiler defines both of these. */
200 #ifdef M_UNIX
201 #undef M_XENIX
202 #endif
204 /* On the sun386i and in System V rel 3, ar.h defines two different archive
205 formats depending upon whether you have defined PORTAR (normal) or PORT5AR
206 (System V Release 1). There is no default, one or the other must be defined
207 to have a nonzero value. */
209 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
210 #undef PORTAR
211 #ifdef M_XENIX
212 /* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
213 PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
214 right one. */
215 #define PORTAR 0
216 #else
217 #define PORTAR 1
218 #endif
219 #endif
221 /* On AIX, define these symbols to be sure to get both archive formats.
222 AIX 4.3 introduced the "big" archive format to support 64-bit object
223 files, so on AIX 4.3 systems we need to support both the "normal" and
224 "big" archive formats. An archive's format is indicated in the
225 "fl_magic" field of the "FL_HDR" structure. For a normal archive,
226 this field will be the string defined by the AIAMAG symbol. For a
227 "big" archive, it will be the string defined by the AIAMAGBIG symbol
228 (at least on AIX it works this way).
230 Note: we'll define these symbols regardless of which AIX version
231 we're compiling on, but this is okay since we'll use the new symbols
232 only if they're present. */
233 #ifdef _AIX
234 # define __AR_SMALL__
235 # define __AR_BIG__
236 #endif
238 #ifndef WINDOWS32
239 # ifndef __BEOS__
240 # include <ar.h>
241 # else
242 /* BeOS 5 doesn't have <ar.h> but has archives in the same format
243 * as many other Unices. This was taken from GNU binutils for BeOS.
245 # define ARMAG "!<arch>\n" /* String that begins an archive file. */
246 # define SARMAG 8 /* Size of that string. */
247 # define ARFMAG "`\n" /* String in ar_fmag at end of each header. */
248 struct ar_hdr
250 char ar_name[16]; /* Member file name, sometimes / terminated. */
251 char ar_date[12]; /* File date, decimal seconds since Epoch. */
252 char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */
253 char ar_mode[8]; /* File mode, in ASCII octal. */
254 char ar_size[10]; /* File size, in ASCII decimal. */
255 char ar_fmag[2]; /* Always contains ARFMAG. */
257 # endif
258 #else
259 /* These should allow us to read Windows (VC++) libraries (according to Frank
260 * Libbrecht <frankl@abzx.belgium.hp.com>)
262 # include <windows.h>
263 # include <windef.h>
264 # include <io.h>
265 # define ARMAG IMAGE_ARCHIVE_START
266 # define SARMAG IMAGE_ARCHIVE_START_SIZE
267 # define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER
268 # define ar_name Name
269 # define ar_mode Mode
270 # define ar_size Size
271 # define ar_date Date
272 # define ar_uid UserID
273 # define ar_gid GroupID
274 #endif
276 /* Cray's <ar.h> apparently defines this. */
277 #ifndef AR_HDR_SIZE
278 # define AR_HDR_SIZE (sizeof (struct ar_hdr))
279 #endif
281 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
283 Open the archive named ARCHIVE, find its members one by one,
284 and for each one call FUNCTION with the following arguments:
285 archive file descriptor for reading the data,
286 member name,
287 member name might be truncated flag,
288 member header position in file,
289 member data position in file,
290 member data size,
291 member date,
292 member uid,
293 member gid,
294 member protection mode,
295 ARG.
297 The descriptor is poised to read the data of the member
298 when FUNCTION is called. It does not matter how much
299 data FUNCTION reads.
301 If FUNCTION returns nonzero, we immediately return
302 what FUNCTION returned.
304 Returns -1 if archive does not exist,
305 Returns -2 if archive has invalid format.
306 Returns 0 if have scanned successfully. */
308 long int
309 ar_scan (archive, function, arg)
310 char *archive;
311 long int (*function) ();
312 long int arg;
314 #ifdef AIAMAG
315 FL_HDR fl_header;
316 #ifdef AIAMAGBIG
317 int big_archive = 0;
318 FL_HDR_BIG fl_header_big;
319 #endif
320 #else
321 int long_name = 0;
322 #endif
323 char *namemap = 0;
324 register int desc = open (archive, O_RDONLY, 0);
325 if (desc < 0)
326 return -1;
327 #ifdef SARMAG
329 char buf[SARMAG];
330 register int nread = read (desc, buf, SARMAG);
331 if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
333 (void) close (desc);
334 return -2;
337 #else
338 #ifdef AIAMAG
340 register int nread = read (desc, (char *) &fl_header, FL_HSZ);
342 if (nread != FL_HSZ)
344 (void) close (desc);
345 return -2;
347 #ifdef AIAMAGBIG
348 /* If this is a "big" archive, then set the flag and
349 re-read the header into the "big" structure. */
350 if (!bcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
352 big_archive = 1;
354 /* seek back to beginning of archive */
355 if (lseek (desc, 0, 0) < 0)
357 (void) close (desc);
358 return -2;
361 /* re-read the header into the "big" structure */
362 nread = read (desc, (char *) &fl_header_big, FL_HSZ_BIG);
363 if (nread != FL_HSZ_BIG)
365 (void) close (desc);
366 return -2;
369 else
370 #endif
371 /* Check to make sure this is a "normal" archive. */
372 if (bcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
374 (void) close (desc);
375 return -2;
378 #else
380 #ifndef M_XENIX
381 int buf;
382 #else
383 unsigned short int buf;
384 #endif
385 register int nread = read(desc, &buf, sizeof (buf));
386 if (nread != sizeof (buf) || buf != ARMAG)
388 (void) close (desc);
389 return -2;
392 #endif
393 #endif
395 /* Now find the members one by one. */
397 #ifdef SARMAG
398 register long int member_offset = SARMAG;
399 #else
400 #ifdef AIAMAG
401 long int member_offset;
402 long int last_member_offset;
404 #ifdef AIAMAGBIG
405 if ( big_archive )
407 sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
408 sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
410 else
411 #endif
413 sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
414 sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
417 if (member_offset == 0)
419 /* Empty archive. */
420 close (desc);
421 return 0;
423 #else
424 #ifndef M_XENIX
425 register long int member_offset = sizeof (int);
426 #else /* Xenix. */
427 register long int member_offset = sizeof (unsigned short int);
428 #endif /* Not Xenix. */
429 #endif
430 #endif
432 while (1)
434 register int nread;
435 struct ar_hdr member_header;
436 #ifdef AIAMAGBIG
437 struct ar_hdr_big member_header_big;
438 #endif
439 #ifdef AIAMAG
440 char name[256];
441 int name_len;
442 long int dateval;
443 int uidval, gidval;
444 long int data_offset;
445 #else
446 char namebuf[sizeof member_header.ar_name + 1];
447 char *name;
448 int is_namemap; /* Nonzero if this entry maps long names. */
449 #endif
450 long int eltsize;
451 int eltmode;
452 long int fnval;
454 if (lseek (desc, member_offset, 0) < 0)
456 (void) close (desc);
457 return -2;
460 #ifdef AIAMAG
461 #define AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
463 #ifdef AIAMAGBIG
464 if (big_archive)
466 nread = read (desc, (char *) &member_header_big,
467 AR_MEMHDR_SZ(member_header_big) );
469 if (nread != AR_MEMHDR_SZ(member_header_big))
471 (void) close (desc);
472 return -2;
475 sscanf (member_header_big.ar_namlen, "%4d", &name_len);
476 nread = read (desc, name, name_len);
478 if (nread != name_len)
480 (void) close (desc);
481 return -2;
484 name[name_len] = 0;
486 sscanf (member_header_big.ar_date, "%12ld", &dateval);
487 sscanf (member_header_big.ar_uid, "%12d", &uidval);
488 sscanf (member_header_big.ar_gid, "%12d", &gidval);
489 sscanf (member_header_big.ar_mode, "%12o", &eltmode);
490 sscanf (member_header_big.ar_size, "%20ld", &eltsize);
492 data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
493 + name_len + 2);
495 else
496 #endif
498 nread = read (desc, (char *) &member_header,
499 AR_MEMHDR_SZ(member_header) );
501 if (nread != AR_MEMHDR_SZ(member_header))
503 (void) close (desc);
504 return -2;
507 sscanf (member_header.ar_namlen, "%4d", &name_len);
508 nread = read (desc, name, name_len);
510 if (nread != name_len)
512 (void) close (desc);
513 return -2;
516 name[name_len] = 0;
518 sscanf (member_header.ar_date, "%12ld", &dateval);
519 sscanf (member_header.ar_uid, "%12d", &uidval);
520 sscanf (member_header.ar_gid, "%12d", &gidval);
521 sscanf (member_header.ar_mode, "%12o", &eltmode);
522 sscanf (member_header.ar_size, "%12ld", &eltsize);
524 data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
525 + name_len + 2);
527 data_offset += data_offset % 2;
529 fnval =
530 (*function) (desc, name, 0,
531 member_offset, data_offset, eltsize,
532 dateval, uidval, gidval,
533 eltmode, arg);
535 #else /* Not AIAMAG. */
536 nread = read (desc, (char *) &member_header, AR_HDR_SIZE);
537 if (nread == 0)
538 /* No data left means end of file; that is OK. */
539 break;
541 if (nread != AR_HDR_SIZE
542 #if defined(ARFMAG) || defined(ARFZMAG)
543 || (
544 # ifdef ARFMAG
545 bcmp (member_header.ar_fmag, ARFMAG, 2)
546 # else
548 # endif
550 # ifdef ARFZMAG
551 bcmp (member_header.ar_fmag, ARFZMAG, 2)
552 # else
554 # endif
556 #endif
559 (void) close (desc);
560 return -2;
563 name = namebuf;
564 bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
566 register char *p = name + sizeof member_header.ar_name;
568 *p = '\0';
569 while (p > name && *--p == ' ');
571 #ifndef AIAMAG
572 /* If the member name is "//" or "ARFILENAMES/" this may be
573 a list of file name mappings. The maximum file name
574 length supported by the standard archive format is 14
575 characters. This member will actually always be the
576 first or second entry in the archive, but we don't check
577 that. */
578 is_namemap = (!strcmp (name, "//")
579 || !strcmp (name, "ARFILENAMES/"));
580 #endif /* Not AIAMAG. */
581 /* On some systems, there is a slash after each member name. */
582 if (*p == '/')
583 *p = '\0';
585 #ifndef AIAMAG
586 /* If the member name starts with a space or a slash, this
587 is an index into the file name mappings (used by GNU ar).
588 Otherwise if the member name looks like #1/NUMBER the
589 real member name appears in the element data (used by
590 4.4BSD). */
591 if (! is_namemap
592 && (name[0] == ' ' || name[0] == '/')
593 && namemap != 0)
595 name = namemap + atoi (name + 1);
596 long_name = 1;
598 else if (name[0] == '#'
599 && name[1] == '1'
600 && name[2] == '/')
602 int namesize = atoi (name + 3);
604 name = (char *) alloca (namesize + 1);
605 nread = read (desc, name, namesize);
606 if (nread != namesize)
608 close (desc);
609 return -2;
611 name[namesize] = '\0';
613 long_name = 1;
615 #endif /* Not AIAMAG. */
618 #ifndef M_XENIX
619 sscanf (member_header.ar_mode, "%o", &eltmode);
620 eltsize = atol (member_header.ar_size);
621 #else /* Xenix. */
622 eltmode = (unsigned short int) member_header.ar_mode;
623 eltsize = member_header.ar_size;
624 #endif /* Not Xenix. */
626 fnval =
627 (*function) (desc, name, ! long_name, member_offset,
628 member_offset + AR_HDR_SIZE, eltsize,
629 #ifndef M_XENIX
630 atol (member_header.ar_date),
631 atoi (member_header.ar_uid),
632 atoi (member_header.ar_gid),
633 #else /* Xenix. */
634 member_header.ar_date,
635 member_header.ar_uid,
636 member_header.ar_gid,
637 #endif /* Not Xenix. */
638 eltmode, arg);
640 #endif /* AIAMAG. */
642 if (fnval)
644 (void) close (desc);
645 return fnval;
648 #ifdef AIAMAG
649 if (member_offset == last_member_offset)
650 /* End of the chain. */
651 break;
653 #ifdef AIAMAGBIG
654 if (big_archive)
655 sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
656 else
657 #endif
658 sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
660 if (lseek (desc, member_offset, 0) != member_offset)
662 (void) close (desc);
663 return -2;
665 #else
667 /* If this member maps archive names, we must read it in. The
668 name map will always precede any members whose names must
669 be mapped. */
670 if (is_namemap)
672 char *clear;
673 char *limit;
675 namemap = (char *) alloca (eltsize);
676 nread = read (desc, namemap, eltsize);
677 if (nread != eltsize)
679 (void) close (desc);
680 return -2;
683 /* The names are separated by newlines. Some formats have
684 a trailing slash. Null terminate the strings for
685 convenience. */
686 limit = namemap + eltsize;
687 for (clear = namemap; clear < limit; clear++)
689 if (*clear == '\n')
691 *clear = '\0';
692 if (clear[-1] == '/')
693 clear[-1] = '\0';
697 is_namemap = 0;
700 member_offset += AR_HDR_SIZE + eltsize;
701 if (member_offset % 2 != 0)
702 member_offset++;
703 #endif
707 close (desc);
708 return 0;
710 #endif /* !VMS */
712 /* Return nonzero iff NAME matches MEM.
713 If TRUNCATED is nonzero, MEM may be truncated to
714 sizeof (struct ar_hdr.ar_name) - 1. */
717 ar_name_equal (name, mem, truncated)
718 char *name, *mem;
719 int truncated;
721 char *p;
723 p = strrchr (name, '/');
724 if (p != 0)
725 name = p + 1;
727 #ifndef VMS
728 if (truncated)
730 #ifdef AIAMAG
731 /* TRUNCATED should never be set on this system. */
732 abort ();
733 #else
734 struct ar_hdr hdr;
735 #if !defined (__hpux) && !defined (cray)
736 return strneq (name, mem, sizeof(hdr.ar_name) - 1);
737 #else
738 return strneq (name, mem, sizeof(hdr.ar_name) - 2);
739 #endif /* !__hpux && !cray */
740 #endif /* !AIAMAG */
742 #endif /* !VMS */
744 return !strcmp (name, mem);
747 #ifndef VMS
748 /* ARGSUSED */
749 static long int
750 ar_member_pos (desc, mem, truncated,
751 hdrpos, datapos, size, date, uid, gid, mode, name)
752 int desc;
753 char *mem;
754 int truncated;
755 long int hdrpos, datapos, size, date;
756 int uid, gid, mode;
757 char *name;
759 if (!ar_name_equal (name, mem, truncated))
760 return 0;
761 return hdrpos;
764 /* Set date of member MEMNAME in archive ARNAME to current time.
765 Returns 0 if successful,
766 -1 if file ARNAME does not exist,
767 -2 if not a valid archive,
768 -3 if other random system call error (including file read-only),
769 1 if valid but member MEMNAME does not exist. */
772 ar_member_touch (arname, memname)
773 char *arname, *memname;
775 register long int pos = ar_scan (arname, ar_member_pos, (long int) memname);
776 register int fd;
777 struct ar_hdr ar_hdr;
778 register int i;
779 struct stat statbuf;
781 if (pos < 0)
782 return (int) pos;
783 if (!pos)
784 return 1;
786 fd = open (arname, O_RDWR, 0666);
787 if (fd < 0)
788 return -3;
789 /* Read in this member's header */
790 if (lseek (fd, pos, 0) < 0)
791 goto lose;
792 if (AR_HDR_SIZE != read (fd, (char *) &ar_hdr, AR_HDR_SIZE))
793 goto lose;
794 /* Write back the header, thus touching the archive file. */
795 if (lseek (fd, pos, 0) < 0)
796 goto lose;
797 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
798 goto lose;
799 /* The file's mtime is the time we we want. */
800 if (fstat (fd, &statbuf) < 0)
801 goto lose;
802 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
803 /* Advance member's time to that time */
804 for (i = 0; i < sizeof ar_hdr.ar_date; i++)
805 ar_hdr.ar_date[i] = ' ';
806 sprintf (ar_hdr.ar_date, "%ld", (long int) statbuf.st_mtime);
807 #ifdef AIAMAG
808 ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
809 #endif
810 #else
811 ar_hdr.ar_date = statbuf.st_mtime;
812 #endif
813 /* Write back this member's header */
814 if (lseek (fd, pos, 0) < 0)
815 goto lose;
816 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
817 goto lose;
818 close (fd);
819 return 0;
821 lose:
822 i = errno;
823 close (fd);
824 errno = i;
825 return -3;
827 #endif
829 #ifdef TEST
831 long int
832 describe_member (desc, name, truncated,
833 hdrpos, datapos, size, date, uid, gid, mode)
834 int desc;
835 char *name;
836 int truncated;
837 long int hdrpos, datapos, size, date;
838 int uid, gid, mode;
840 extern char *ctime ();
842 printf (_("Member `%s'%s: %ld bytes at %ld (%ld).\n"),
843 name, truncated ? _(" (name might be truncated)") : "",
844 size, hdrpos, datapos);
845 printf (_(" Date %s"), ctime (&date));
846 printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
848 return 0;
851 main (argc, argv)
852 int argc;
853 char **argv;
855 ar_scan (argv[1], describe_member);
856 return 0;
859 #endif /* TEST. */
861 #endif /* NO_ARCHIVES. */