Merge changes made in Gnus trunk.
[bpt/emacs.git] / src / dired.c
CommitLineData
14d55bce 1/* Lisp functions for making directory listings.
0b5538bd 2 Copyright (C) 1985, 1986, 1993, 1994, 1999, 2000, 2001, 2002, 2003,
114f9c96 3 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
14d55bce
RS
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
14d55bce 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
14d55bce
RS
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
14d55bce
RS
19
20
3964b9a7
RS
21#include <config.h>
22
14d55bce
RS
23#include <stdio.h>
24#include <sys/types.h>
25#include <sys/stat.h>
d7306fe6 26#include <setjmp.h>
14d55bce 27
5b9c0a1d 28#ifdef HAVE_PWD_H
6b61353c 29#include <pwd.h>
5b9c0a1d 30#endif
6b61353c 31#include <grp.h>
6b61353c 32
7cc9f69f 33#include <errno.h>
68c45bf0 34
dfcf069d
AS
35#ifdef HAVE_UNISTD_H
36#include <unistd.h>
37#endif
38
d6717cdb
JB
39/* The d_nameln member of a struct dirent includes the '\0' character
40 on some systems, but not on others. What's worse, you can't tell
41 at compile-time which one it will be, since it really depends on
42 the sort of system providing the filesystem you're reading from,
43 not the system you are running on. Paul Eggert
44 <eggert@bi.twinsun.com> says this occurs when Emacs is running on a
45 SunOS 4.1.2 host, reading a directory that is remote-mounted from a
46 Solaris 2.1 host and is in a native Solaris 2.1 filesystem.
47
48 Since applying strlen to the name always works, we'll just do that. */
49#define NAMLEN(p) strlen (p->d_name)
50
1c97e857 51#ifdef HAVE_DIRENT_H
14d55bce
RS
52
53#include <dirent.h>
54#define DIRENTRY struct dirent
14d55bce 55
1c97e857 56#else /* not HAVE_DIRENT_H */
14d55bce 57
14d55bce 58#include <sys/dir.h>
851cab13
DL
59#include <sys/stat.h>
60
14d55bce 61#define DIRENTRY struct direct
14d55bce 62
361358ea
JB
63extern DIR *opendir (char *);
64extern struct direct *readdir (DIR *);
14d55bce 65
1c97e857 66#endif /* HAVE_DIRENT_H */
128ecc89 67
9f8c08a7 68#ifdef MSDOS
128ecc89
RS
69#define DIRENTRY_NONEMPTY(p) ((p)->d_name[0] != 0)
70#else
71#define DIRENTRY_NONEMPTY(p) ((p)->d_ino)
14d55bce
RS
72#endif
73
14d55bce 74#include "lisp.h"
fa8459a3 75#include "systime.h"
14d55bce
RS
76#include "buffer.h"
77#include "commands.h"
d2f6dae8 78#include "character.h"
bd33479f
KH
79#include "charset.h"
80#include "coding.h"
14d55bce 81#include "regex.h"
8c8a7c58 82#include "blockinput.h"
14d55bce 83
a11889ab
JB
84/* Returns a search buffer, with a fastmap allocated and ready to go. */
85extern struct re_pattern_buffer *compile_pattern (Lisp_Object,
86 struct re_registers *,
87 Lisp_Object, int, int);
88
851cab13 89/* From filemode.c. Can't go in Lisp.h because of `stat'. */
f57e2426 90extern void filemodestring (struct stat *, char *);
851cab13 91
14d55bce
RS
92/* if system does not have symbolic links, it does not have lstat.
93 In that case, use ordinary stat instead. */
94
95#ifndef S_IFLNK
96#define lstat stat
97#endif
98
65156807 99extern Lisp_Object Vw32_get_true_file_attributes;
ccbcf979 100
14d55bce 101Lisp_Object Vcompletion_ignored_extensions;
32f4334d 102Lisp_Object Qdirectory_files;
4424b255 103Lisp_Object Qdirectory_files_and_attributes;
32f4334d
RS
104Lisp_Object Qfile_name_completion;
105Lisp_Object Qfile_name_all_completions;
434e6714 106Lisp_Object Qfile_attributes;
4424b255 107Lisp_Object Qfile_attributes_lessp;
b3f04ced 108
eec47d6b 109static int scmp (const unsigned char *, const unsigned char *, int);
14d55bce 110\f
65156807
EZ
111#ifdef WINDOWSNT
112Lisp_Object
113directory_files_internal_w32_unwind (Lisp_Object arg)
114{
115 Vw32_get_true_file_attributes = arg;
116 return Qnil;
117}
118#endif
2488aba5
AI
119
120Lisp_Object
971de7fb 121directory_files_internal_unwind (Lisp_Object dh)
2488aba5 122{
9d291bdf 123 DIR *d = (DIR *) XSAVE_VALUE (dh)->pointer;
d15b573e 124 BLOCK_INPUT;
2488aba5 125 closedir (d);
d15b573e 126 UNBLOCK_INPUT;
2488aba5
AI
127 return Qnil;
128}
129
177c0ea7 130/* Function shared by Fdirectory_files and Fdirectory_files_and_attributes.
4424b255 131 When ATTRS is zero, return a list of directory filenames; when
6b61353c
KH
132 non-zero, return a list of directory filenames and their attributes.
133 In the latter case, ID_FORMAT is passed to Ffile_attributes. */
f69f9da1 134
4424b255 135Lisp_Object
971de7fb 136directory_files_internal (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort, int attrs, Lisp_Object id_format)
14d55bce
RS
137{
138 DIR *d;
388ac098
GM
139 int directory_nbytes;
140 Lisp_Object list, dirfilename, encoded_directory;
6bbd7a29 141 struct re_pattern_buffer *bufp = NULL;
96d64004 142 int needsep = 0;
aed13378 143 int count = SPECPDL_INDEX ();
388ac098 144 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
8e42f043 145 DIRENTRY *dp;
65156807
EZ
146#ifdef WINDOWSNT
147 Lisp_Object w32_save = Qnil;
148#endif
32f4334d 149
96d64004 150 /* Because of file name handlers, these functions might call
6155fae1 151 Ffuncall, and cause a GC. */
388ac098
GM
152 list = encoded_directory = dirfilename = Qnil;
153 GCPRO5 (match, directory, list, dirfilename, encoded_directory);
96d64004 154 dirfilename = Fdirectory_file_name (directory);
6155fae1 155
265a9e55 156 if (!NILP (match))
14d55bce 157 {
b7826503 158 CHECK_STRING (match);
ebb9e16f
JB
159
160 /* MATCH might be a flawed regular expression. Rather than
8e6208c5 161 catching and signaling our own errors, we just call
ebb9e16f 162 compile_pattern to do the work for us. */
c872c6b2
RS
163 /* Pass 1 for the MULTIBYTE arg
164 because we do make multibyte strings if the contents warrant. */
1a9fbabe
EZ
165# ifdef WINDOWSNT
166 /* Windows users want case-insensitive wildcards. */
167 bufp = compile_pattern (match, 0,
168 buffer_defaults.case_canon_table, 0, 1);
169# else /* !WINDOWSNT */
3e937712 170 bufp = compile_pattern (match, 0, Qnil, 0, 1);
1a9fbabe 171# endif /* !WINDOWSNT */
14d55bce
RS
172 }
173
b3edfc9b 174 /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run
388ac098
GM
175 run_pre_post_conversion_on_str which calls Lisp directly and
176 indirectly. */
6c8b4f07
SM
177 if (STRING_MULTIBYTE (dirfilename))
178 dirfilename = ENCODE_FILE (dirfilename);
179 encoded_directory = (STRING_MULTIBYTE (directory)
180 ? ENCODE_FILE (directory) : directory);
24c2a54f 181
e50c66d3 182 /* Now *bufp is the compiled form of MATCH; don't call anything
6155fae1
JB
183 which might compile a new regexp until we're done with the loop! */
184
d15b573e 185 BLOCK_INPUT;
d5db4077 186 d = opendir (SDATA (dirfilename));
d15b573e 187 UNBLOCK_INPUT;
388ac098 188 if (d == NULL)
23bd240f 189 report_file_error ("Opening directory", Fcons (directory, Qnil));
14d55bce 190
2488aba5
AI
191 /* Unfortunately, we can now invoke expand-file-name and
192 file-attributes on filenames, both of which can throw, so we must
193 do a proper unwind-protect. */
194 record_unwind_protect (directory_files_internal_unwind,
9d291bdf 195 make_save_value (d, 0));
2488aba5 196
65156807
EZ
197#ifdef WINDOWSNT
198 if (attrs)
199 {
65156807
EZ
200 extern int is_slow_fs (const char *);
201
202 /* Do this only once to avoid doing it (in w32.c:stat) for each
203 file in the directory, when we call Ffile_attributes below. */
204 record_unwind_protect (directory_files_internal_w32_unwind,
205 Vw32_get_true_file_attributes);
206 w32_save = Vw32_get_true_file_attributes;
207 if (EQ (Vw32_get_true_file_attributes, Qlocal))
208 {
65156807
EZ
209 /* w32.c:stat will notice these bindings and avoid calling
210 GetDriveType for each file. */
b6046155 211 if (is_slow_fs (SDATA (dirfilename)))
65156807
EZ
212 Vw32_get_true_file_attributes = Qnil;
213 else
214 Vw32_get_true_file_attributes = Qt;
215 }
216 }
217#endif
218
d5db4077 219 directory_nbytes = SBYTES (directory);
c81a9bdc 220 re_match_object = Qt;
14d55bce 221
96d64004 222 /* Decide whether we need to add a directory separator. */
388ac098 223 if (directory_nbytes == 0
d5db4077 224 || !IS_ANY_SEP (SREF (directory, directory_nbytes - 1)))
96d64004 225 needsep = 1;
96d64004 226
8e42f043 227 /* Loop reading blocks until EOF or error. */
f69f9da1 228 for (;;)
14d55bce 229 {
f69f9da1
GM
230 errno = 0;
231 dp = readdir (d);
232
9d291bdf 233 if (dp == NULL && (0
f69f9da1 234#ifdef EAGAIN
9d291bdf
SM
235 || errno == EAGAIN
236#endif
237#ifdef EINTR
238 || errno == EINTR
f69f9da1 239#endif
9d291bdf
SM
240 ))
241 { QUIT; continue; }
177c0ea7 242
f69f9da1
GM
243 if (dp == NULL)
244 break;
245
128ecc89 246 if (DIRENTRY_NONEMPTY (dp))
14d55bce 247 {
e23f810c 248 int len;
2488aba5 249 int wanted = 0;
388ac098
GM
250 Lisp_Object name, finalname;
251 struct gcpro gcpro1, gcpro2;
e23f810c
KH
252
253 len = NAMLEN (dp);
9ad4f3e5 254 name = finalname = make_unibyte_string (dp->d_name, len);
388ac098 255 GCPRO2 (finalname, name);
177c0ea7 256
6c8b4f07 257 /* Note: DECODE_FILE can GC; it should protect its argument,
388ac098
GM
258 though. */
259 name = DECODE_FILE (name);
d5db4077 260 len = SBYTES (name);
e23f810c 261
2488aba5
AI
262 /* Now that we have unwind_protect in place, we might as well
263 allow matching to be interrupted. */
264 immediate_quit = 1;
265 QUIT;
266
265a9e55 267 if (NILP (match)
d5db4077 268 || (0 <= re_search (bufp, SDATA (name), len, 0, len, 0)))
388ac098 269 wanted = 1;
2488aba5
AI
270
271 immediate_quit = 0;
272
273 if (wanted)
14d55bce 274 {
265a9e55 275 if (!NILP (full))
14d55bce 276 {
e23f810c 277 Lisp_Object fullname;
388ac098
GM
278 int nbytes = len + directory_nbytes + needsep;
279 int nchars;
5617588f 280
388ac098 281 fullname = make_uninit_multibyte_string (nbytes, nbytes);
72af86bd
AS
282 memcpy (SDATA (fullname), SDATA (directory),
283 directory_nbytes);
177c0ea7 284
5617588f 285 if (needsep)
d549c5db 286 SSET (fullname, directory_nbytes, DIRECTORY_SEP);
177c0ea7 287
72af86bd
AS
288 memcpy (SDATA (fullname) + directory_nbytes + needsep,
289 SDATA (name), len);
177c0ea7 290
d5db4077 291 nchars = chars_in_text (SDATA (fullname), nbytes);
388ac098
GM
292
293 /* Some bug somewhere. */
294 if (nchars > nbytes)
295 abort ();
177c0ea7 296
437fcd47 297 STRING_SET_CHARS (fullname, nchars);
388ac098 298 if (nchars == nbytes)
d5db4077 299 STRING_SET_UNIBYTE (fullname);
177c0ea7 300
4424b255
GV
301 finalname = fullname;
302 }
aab9c564
KH
303 else
304 finalname = name;
4424b255
GV
305
306 if (attrs)
307 {
308 /* Construct an expanded filename for the directory entry.
309 Use the decoded names for input to Ffile_attributes. */
388ac098
GM
310 Lisp_Object decoded_fullname, fileattrs;
311 struct gcpro gcpro1, gcpro2;
312
313 decoded_fullname = fileattrs = Qnil;
314 GCPRO2 (decoded_fullname, fileattrs);
4424b255 315
388ac098 316 /* Both Fexpand_file_name and Ffile_attributes can GC. */
4424b255 317 decoded_fullname = Fexpand_file_name (name, directory);
6b61353c 318 fileattrs = Ffile_attributes (decoded_fullname, id_format);
4424b255
GV
319
320 list = Fcons (Fcons (finalname, fileattrs), list);
388ac098 321 UNGCPRO;
4424b255
GV
322 }
323 else
388ac098 324 list = Fcons (finalname, list);
14d55bce 325 }
388ac098
GM
326
327 UNGCPRO;
14d55bce
RS
328 }
329 }
2488aba5 330
d15b573e 331 BLOCK_INPUT;
14d55bce 332 closedir (d);
d15b573e 333 UNBLOCK_INPUT;
65156807
EZ
334#ifdef WINDOWSNT
335 if (attrs)
336 Vw32_get_true_file_attributes = w32_save;
337#endif
2488aba5
AI
338
339 /* Discard the unwind protect. */
340 specpdl_ptr = specpdl + count;
341
388ac098
GM
342 if (NILP (nosort))
343 list = Fsort (Fnreverse (list),
344 attrs ? Qfile_attributes_lessp : Qstring_lessp);
177c0ea7 345
388ac098 346 RETURN_UNGCPRO (list);
14d55bce 347}
4424b255
GV
348
349
350DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 4, 0,
335c5470
PJ
351 doc: /* Return a list of names of files in DIRECTORY.
352There are three optional arguments:
353If FULL is non-nil, return absolute file names. Otherwise return names
354 that are relative to the specified directory.
355If MATCH is non-nil, mention only file names that match the regexp MATCH.
356If NOSORT is non-nil, the list is not sorted--its order is unpredictable.
a489517b
JB
357 Otherwise, the list returned is sorted with `string-lessp'.
358 NOSORT is useful if you plan to sort the result yourself. */)
5842a27b 359 (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort)
4424b255
GV
360{
361 Lisp_Object handler;
4ece81a6 362 directory = Fexpand_file_name (directory, Qnil);
4424b255
GV
363
364 /* If the file name has special constructs in it,
365 call the corresponding file handler. */
366 handler = Ffind_file_name_handler (directory, Qdirectory_files);
367 if (!NILP (handler))
6b61353c
KH
368 return call5 (handler, Qdirectory_files, directory,
369 full, match, nosort);
4424b255 370
6b61353c 371 return directory_files_internal (directory, full, match, nosort, 0, Qnil);
4424b255
GV
372}
373
335c5470 374DEFUN ("directory-files-and-attributes", Fdirectory_files_and_attributes,
6b61353c 375 Sdirectory_files_and_attributes, 1, 5, 0,
335c5470 376 doc: /* Return a list of names of files and their attributes in DIRECTORY.
6b61353c 377There are four optional arguments:
335c5470
PJ
378If FULL is non-nil, return absolute file names. Otherwise return names
379 that are relative to the specified directory.
380If MATCH is non-nil, mention only file names that match the regexp MATCH.
381If NOSORT is non-nil, the list is not sorted--its order is unpredictable.
6b61353c
KH
382 NOSORT is useful if you plan to sort the result yourself.
383ID-FORMAT specifies the preferred format of attributes uid and gid, see
6c5665e9
EZ
384`file-attributes' for further documentation.
385On MS-Windows, performance depends on `w32-get-true-file-attributes',
386which see. */)
5842a27b 387 (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort, Lisp_Object id_format)
4424b255
GV
388{
389 Lisp_Object handler;
4ece81a6 390 directory = Fexpand_file_name (directory, Qnil);
4424b255
GV
391
392 /* If the file name has special constructs in it,
393 call the corresponding file handler. */
394 handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes);
395 if (!NILP (handler))
6b61353c
KH
396 return call6 (handler, Qdirectory_files_and_attributes,
397 directory, full, match, nosort, id_format);
4424b255 398
6b61353c 399 return directory_files_internal (directory, full, match, nosort, 1, id_format);
4424b255
GV
400}
401
14d55bce 402\f
971de7fb 403Lisp_Object file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int ver_flag, Lisp_Object predicate);
14d55bce
RS
404
405DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion,
abfb1932 406 2, 3, 0,
335c5470
PJ
407 doc: /* Complete file name FILE in directory DIRECTORY.
408Returns the longest string
409common to all file names in DIRECTORY that start with FILE.
410If there is only one and FILE matches it exactly, returns t.
2f60660a 411Returns nil if DIRECTORY contains no name starting with FILE.
335c5470 412
b6ce54d6
RS
413If PREDICATE is non-nil, call PREDICATE with each possible
414completion (in absolute form) and ignore it if PREDICATE returns nil.
415
335c5470
PJ
416This function ignores some of the possible completions as
417determined by the variable `completion-ignored-extensions', which see. */)
5842a27b 418 (Lisp_Object file, Lisp_Object directory, Lisp_Object predicate)
14d55bce 419{
32f4334d 420 Lisp_Object handler;
32f4334d 421
8436e231 422 /* If the directory name has special constructs in it,
32f4334d 423 call the corresponding file handler. */
23bd240f 424 handler = Ffind_file_name_handler (directory, Qfile_name_completion);
32f4334d 425 if (!NILP (handler))
abfb1932 426 return call4 (handler, Qfile_name_completion, file, directory, predicate);
32f4334d 427
8436e231
RS
428 /* If the file name has special constructs in it,
429 call the corresponding file handler. */
430 handler = Ffind_file_name_handler (file, Qfile_name_completion);
431 if (!NILP (handler))
abfb1932 432 return call4 (handler, Qfile_name_completion, file, directory, predicate);
8436e231 433
abfb1932 434 return file_name_completion (file, directory, 0, 0, predicate);
14d55bce
RS
435}
436
437DEFUN ("file-name-all-completions", Ffile_name_all_completions,
335c5470
PJ
438 Sfile_name_all_completions, 2, 2, 0,
439 doc: /* Return a list of all completions of file name FILE in directory DIRECTORY.
440These are all file names in directory DIRECTORY which begin with FILE. */)
5842a27b 441 (Lisp_Object file, Lisp_Object directory)
14d55bce 442{
32f4334d
RS
443 Lisp_Object handler;
444
8436e231 445 /* If the directory name has special constructs in it,
32f4334d 446 call the corresponding file handler. */
23bd240f 447 handler = Ffind_file_name_handler (directory, Qfile_name_all_completions);
32f4334d 448 if (!NILP (handler))
23bd240f 449 return call3 (handler, Qfile_name_all_completions, file, directory);
32f4334d 450
8436e231
RS
451 /* If the file name has special constructs in it,
452 call the corresponding file handler. */
453 handler = Ffind_file_name_handler (file, Qfile_name_all_completions);
454 if (!NILP (handler))
23bd240f 455 return call3 (handler, Qfile_name_all_completions, file, directory);
8436e231 456
abfb1932 457 return file_name_completion (file, directory, 1, 0, Qnil);
14d55bce
RS
458}
459
438105ed 460static int file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_addr);
01bb4018 461Lisp_Object Qdefault_directory;
dfcf069d 462
14d55bce 463Lisp_Object
971de7fb 464file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, int ver_flag, Lisp_Object predicate)
14d55bce
RS
465{
466 DIR *d;
3271a8f5 467 int bestmatchsize = 0;
14d55bce 468 int matchcount = 0;
abfb1932
RS
469 /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded.
470 If ALL_FLAG is 0, BESTMATCH is either nil
471 or the best match so far, not decoded. */
14d55bce 472 Lisp_Object bestmatch, tem, elt, name;
24c2a54f
RS
473 Lisp_Object encoded_file;
474 Lisp_Object encoded_dir;
14d55bce
RS
475 struct stat st;
476 int directoryp;
3271a8f5
SM
477 /* If includeall is zero, exclude files in completion-ignored-extensions as
478 well as "." and "..". Until shown otherwise, assume we can't exclude
479 anything. */
480 int includeall = 1;
aed13378 481 int count = SPECPDL_INDEX ();
24c2a54f 482 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
3fcc88cc 483
6bbd7a29
GM
484 elt = Qnil;
485
b7826503 486 CHECK_STRING (file);
14d55bce 487
128ecc89
RS
488#ifdef FILE_SYSTEM_CASE
489 file = FILE_SYSTEM_CASE (file);
490#endif
14d55bce 491 bestmatch = Qnil;
24c2a54f
RS
492 encoded_file = encoded_dir = Qnil;
493 GCPRO5 (file, dirname, bestmatch, encoded_file, encoded_dir);
3fcc88cc 494 dirname = Fexpand_file_name (dirname, Qnil);
01bb4018 495 specbind (Qdefault_directory, dirname);
14d55bce 496
24c2a54f
RS
497 /* Do completion on the encoded file name
498 because the other names in the directory are (we presume)
499 encoded likewise. We decode the completed string at the end. */
2a54a229
SM
500 /* Actually, this is not quite true any more: we do most of the completion
501 work with decoded file names, but we still do some filtering based
502 on the encoded file name. */
6c8b4f07 503 encoded_file = STRING_MULTIBYTE (file) ? ENCODE_FILE (file) : file;
24c2a54f
RS
504
505 encoded_dir = ENCODE_FILE (dirname);
506
3271a8f5
SM
507 BLOCK_INPUT;
508 d = opendir (SDATA (Fdirectory_file_name (encoded_dir)));
509 UNBLOCK_INPUT;
510 if (!d)
511 report_file_error ("Opening directory", Fcons (dirname, Qnil));
14d55bce 512
3271a8f5
SM
513 record_unwind_protect (directory_files_internal_unwind,
514 make_save_value (d, 0));
14d55bce 515
3271a8f5
SM
516 /* Loop reading blocks */
517 /* (att3b compiler bug requires do a null comparison this way) */
518 while (1)
14d55bce 519 {
3271a8f5
SM
520 DIRENTRY *dp;
521 int len;
522 int canexclude = 0;
14d55bce 523
3271a8f5
SM
524 errno = 0;
525 dp = readdir (d);
526 if (dp == NULL && (0
9d291bdf 527# ifdef EAGAIN
3271a8f5 528 || errno == EAGAIN
9d291bdf
SM
529# endif
530# ifdef EINTR
3271a8f5 531 || errno == EINTR
9d291bdf 532# endif
3271a8f5
SM
533 ))
534 { QUIT; continue; }
9d291bdf 535
3271a8f5 536 if (!dp) break;
14d55bce 537
3271a8f5 538 len = NAMLEN (dp);
14d55bce 539
3271a8f5
SM
540 QUIT;
541 if (! DIRENTRY_NONEMPTY (dp)
542 || len < SCHARS (encoded_file)
543 || 0 <= scmp (dp->d_name, SDATA (encoded_file),
544 SCHARS (encoded_file)))
545 continue;
14d55bce 546
3271a8f5
SM
547 if (file_name_completion_stat (encoded_dir, dp, &st) < 0)
548 continue;
14d55bce 549
3271a8f5
SM
550 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
551 tem = Qnil;
552 /* If all_flag is set, always include all.
553 It would not actually be helpful to the user to ignore any possible
554 completions when making a list of them. */
555 if (!all_flag)
556 {
557 int skip;
2cd298e2 558
7519c40d 559#if 0 /* FIXME: The `scmp' call compares an encoded and a decoded string. */
2cd298e2
SM
560 /* If this entry matches the current bestmatch, the only
561 thing it can do is increase matchcount, so don't bother
562 investigating it any further. */
563 if (!completion_ignore_case
564 /* The return result depends on whether it's the sole match. */
565 && matchcount > 1
566 && !includeall /* This match may allow includeall to 0. */
567 && len >= bestmatchsize
568 && 0 > scmp (dp->d_name, SDATA (bestmatch), bestmatchsize))
569 continue;
7519c40d 570#endif
2cd298e2 571
3271a8f5 572 if (directoryp)
ad456ad4
RS
573 {
574#ifndef TRIVIAL_DIRECTORY_ENTRY
575#define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
576#endif
abfb1932
RS
577 /* "." and ".." are never interesting as completions, and are
578 actually in the way in a directory with only one file. */
3271a8f5
SM
579 if (TRIVIAL_DIRECTORY_ENTRY (dp->d_name))
580 canexclude = 1;
581 else if (len > SCHARS (encoded_file))
d013f29b
EZ
582 /* Ignore directories if they match an element of
583 completion-ignored-extensions which ends in a slash. */
584 for (tem = Vcompletion_ignored_extensions;
585 CONSP (tem); tem = XCDR (tem))
586 {
587 int elt_len;
2a54a229 588 unsigned char *p1;
d013f29b
EZ
589
590 elt = XCAR (tem);
591 if (!STRINGP (elt))
592 continue;
a74aaa9d
EZ
593 /* Need to encode ELT, since scmp compares unibyte
594 strings only. */
595 elt = ENCODE_FILE (elt);
d5db4077 596 elt_len = SCHARS (elt) - 1; /* -1 for trailing / */
7a8d465a 597 if (elt_len <= 0)
d013f29b 598 continue;
d5db4077 599 p1 = SDATA (elt);
d013f29b
EZ
600 if (p1[elt_len] != '/')
601 continue;
602 skip = len - elt_len;
603 if (skip < 0)
604 continue;
605
606 if (0 <= scmp (dp->d_name + skip, p1, elt_len))
607 continue;
608 break;
609 }
ad456ad4
RS
610 }
611 else
3271a8f5 612 {
14d55bce
RS
613 /* Compare extensions-to-be-ignored against end of this file name */
614 /* if name is not an exact match against specified string */
3271a8f5 615 if (len > SCHARS (encoded_file))
14d55bce
RS
616 /* and exit this for loop if a match is found */
617 for (tem = Vcompletion_ignored_extensions;
70949dac 618 CONSP (tem); tem = XCDR (tem))
14d55bce 619 {
70949dac 620 elt = XCAR (tem);
88cf1852 621 if (!STRINGP (elt)) continue;
a74aaa9d
EZ
622 /* Need to encode ELT, since scmp compares unibyte
623 strings only. */
624 elt = ENCODE_FILE (elt);
d5db4077 625 skip = len - SCHARS (elt);
14d55bce
RS
626 if (skip < 0) continue;
627
628 if (0 <= scmp (dp->d_name + skip,
d5db4077
KR
629 SDATA (elt),
630 SCHARS (elt)))
14d55bce
RS
631 continue;
632 break;
633 }
634 }
635
f676868d
KH
636 /* If an ignored-extensions match was found,
637 don't process this name as a completion. */
3271a8f5
SM
638 if (CONSP (tem))
639 canexclude = 1;
f676868d 640
3271a8f5
SM
641 if (!includeall && canexclude)
642 /* We're not including all files and this file can be excluded. */
643 continue;
9c691c00 644
3271a8f5
SM
645 if (includeall && !canexclude)
646 { /* If we have one non-excludable file, we want to exclude the
647 excudable files. */
648 includeall = 0;
649 /* Throw away any previous excludable match found. */
650 bestmatch = Qnil;
651 bestmatchsize = 0;
652 matchcount = 0;
f676868d 653 }
3271a8f5
SM
654 }
655 /* FIXME: If we move this `decode' earlier we can eliminate
656 the repeated ENCODE_FILE on Vcompletion_ignored_extensions. */
657 name = make_unibyte_string (dp->d_name, len);
658 name = DECODE_FILE (name);
659
660 {
661 Lisp_Object regexps;
662 Lisp_Object zero;
663 XSETFASTINT (zero, 0);
664
665 /* Ignore this element if it fails to match all the regexps. */
cc524e3b
CY
666 if (completion_ignore_case)
667 {
668 for (regexps = Vcompletion_regexp_list; CONSP (regexps);
669 regexps = XCDR (regexps))
670 if (fast_string_match_ignore_case (XCAR (regexps), name) < 0)
671 break;
672 }
673 else
674 {
675 for (regexps = Vcompletion_regexp_list; CONSP (regexps);
676 regexps = XCDR (regexps))
677 if (fast_string_match (XCAR (regexps), name) < 0)
678 break;
679 }
680
3271a8f5
SM
681 if (CONSP (regexps))
682 continue;
683 }
684
685 /* This is a possible completion */
686 if (directoryp)
687 /* This completion is a directory; make it end with '/'. */
688 name = Ffile_name_as_directory (name);
689
690 /* Test the predicate, if any. */
691 if (!NILP (predicate))
692 {
693 Lisp_Object val;
694 struct gcpro gcpro1;
14d55bce 695
3271a8f5
SM
696 GCPRO1 (name);
697 val = call1 (predicate, name);
698 UNGCPRO;
c4c52bb7 699
3271a8f5
SM
700 if (NILP (val))
701 continue;
702 }
abfb1932 703
3271a8f5 704 /* Suitably record this match. */
14d55bce 705
3271a8f5 706 matchcount++;
f676868d 707
3271a8f5
SM
708 if (all_flag)
709 bestmatch = Fcons (name, bestmatch);
710 else if (NILP (bestmatch))
711 {
712 bestmatch = name;
713 bestmatchsize = SCHARS (name);
714 }
715 else
716 {
717 Lisp_Object zero = make_number (0);
718 /* FIXME: This is a copy of the code in Ftry_completion. */
719 int compare = min (bestmatchsize, SCHARS (name));
720 Lisp_Object tem
721 = Fcompare_strings (bestmatch, zero,
722 make_number (compare),
723 name, zero,
724 make_number (compare),
725 completion_ignore_case ? Qt : Qnil);
726 int matchsize
727 = (EQ (tem, Qt) ? compare
728 : XINT (tem) < 0 ? - XINT (tem) - 1
729 : XINT (tem) - 1);
730
731 if (completion_ignore_case)
f676868d 732 {
3271a8f5
SM
733 /* If this is an exact match except for case,
734 use it as the best match rather than one that is not
735 an exact match. This way, we get the case pattern
736 of the actual match. */
737 /* This tests that the current file is an exact match
738 but BESTMATCH is not (it is too long). */
739 if ((matchsize == SCHARS (name)
2cd298e2 740 && matchsize + !!directoryp < SCHARS (bestmatch))
3271a8f5
SM
741 ||
742 /* If there is no exact match ignoring case,
743 prefer a match that does not change the case
744 of the input. */
745 /* If there is more than one exact match aside from
746 case, and one of them is exact including case,
747 prefer that one. */
748 /* This == checks that, of current file and BESTMATCH,
749 either both or neither are exact. */
750 (((matchsize == SCHARS (name))
751 ==
752 (matchsize + !!directoryp == SCHARS (bestmatch)))
753 && (tem = Fcompare_strings (name, zero,
754 make_number (SCHARS (file)),
755 file, zero,
756 Qnil,
757 Qnil),
758 EQ (Qt, tem))
759 && (tem = Fcompare_strings (bestmatch, zero,
760 make_number (SCHARS (file)),
761 file, zero,
762 Qnil,
763 Qnil),
764 ! EQ (Qt, tem))))
765 bestmatch = name;
14d55bce 766 }
3271a8f5 767 bestmatchsize = matchsize;
2cd298e2
SM
768
769 /* If the best completion so far is reduced to the string
770 we're trying to complete, then we already know there's no
771 other completion, so there's no point looking any further. */
772 if (matchsize <= SCHARS (file)
773 && !includeall /* A future match may allow includeall to 0. */
774 /* If completion-ignore-case is non-nil, don't
775 short-circuit because we want to find the best
776 possible match *including* case differences. */
777 && (!completion_ignore_case || matchsize == 0)
778 /* The return value depends on whether it's the sole match. */
779 && matchcount > 1)
780 break;
781
14d55bce 782 }
14d55bce
RS
783 }
784
3fcc88cc 785 UNGCPRO;
3271a8f5 786 /* This closes the directory. */
c3a3229c 787 bestmatch = unbind_to (count, bestmatch);
14d55bce 788
265a9e55 789 if (all_flag || NILP (bestmatch))
2a54a229 790 return bestmatch;
928b5acc
SM
791 /* Return t if the supplied string is an exact match (counting case);
792 it does not require any change to be made. */
793 if (matchcount == 1 && !NILP (Fequal (bestmatch, file)))
14d55bce 794 return Qt;
24c2a54f
RS
795 bestmatch = Fsubstring (bestmatch, make_number (0),
796 make_number (bestmatchsize));
24c2a54f 797 return bestmatch;
14d55bce
RS
798}
799
b3f04ced
RS
800/* Compare exactly LEN chars of strings at S1 and S2,
801 ignoring case if appropriate.
802 Return -1 if strings match,
803 else number of chars that match at the beginning. */
804
805static int
eec47d6b 806scmp (const unsigned char *s1, const unsigned char *s2, int len)
b3f04ced
RS
807{
808 register int l = len;
809
810 if (completion_ignore_case)
811 {
812 while (l && DOWNCASE (*s1++) == DOWNCASE (*s2++))
813 l--;
814 }
815 else
816 {
817 while (l && *s1++ == *s2++)
818 l--;
819 }
820 if (l == 0)
821 return -1;
822 else
823 return len - l;
824}
825
dfcf069d 826static int
438105ed 827file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_addr)
14d55bce
RS
828{
829 int len = NAMLEN (dp);
d5db4077 830 int pos = SCHARS (dirname);
7e3cf34f 831 int value;
14d55bce
RS
832 char *fullname = (char *) alloca (len + pos + 2);
833
04924ee3 834#ifdef MSDOS
04924ee3
RS
835 /* Some fields of struct stat are *very* expensive to compute on MS-DOS,
836 but aren't required here. Avoid computing the following fields:
837 st_inode, st_size and st_nlink for directories, and the execute bits
838 in st_mode for non-directory files with non-standard extensions. */
839
840 unsigned short save_djstat_flags = _djstat_flags;
841
842 _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
04924ee3
RS
843#endif /* MSDOS */
844
72af86bd 845 memcpy (fullname, SDATA (dirname), pos);
0b39d75d
RS
846 if (!IS_DIRECTORY_SEP (fullname[pos - 1]))
847 fullname[pos++] = DIRECTORY_SEP;
14d55bce 848
72af86bd 849 memcpy (fullname + pos, dp->d_name, len);
14d55bce
RS
850 fullname[pos + len] = 0;
851
a889bd0e 852#ifdef S_IFLNK
7e3cf34f
RS
853 /* We want to return success if a link points to a nonexistent file,
854 but we want to return the status for what the link points to,
855 in case it is a directory. */
856 value = lstat (fullname, st_addr);
857 stat (fullname, st_addr);
858 return value;
a889bd0e 859#else
04924ee3
RS
860 value = stat (fullname, st_addr);
861#ifdef MSDOS
04924ee3 862 _djstat_flags = save_djstat_flags;
04924ee3
RS
863#endif /* MSDOS */
864 return value;
865#endif /* S_IFLNK */
14d55bce
RS
866}
867\f
868Lisp_Object
971de7fb 869make_time (time_t time)
14d55bce
RS
870{
871 return Fcons (make_number (time >> 16),
872 Fcons (make_number (time & 0177777), Qnil));
873}
874
8aaaec6b
EZ
875static char *
876stat_uname (struct stat *st)
877{
878#ifdef WINDOWSNT
879 return st->st_uname;
880#else
881 struct passwd *pw = (struct passwd *) getpwuid (st->st_uid);
882
883 if (pw)
884 return pw->pw_name;
885 else
886 return NULL;
887#endif
888}
889
890static char *
891stat_gname (struct stat *st)
892{
893#ifdef WINDOWSNT
894 return st->st_gname;
895#else
896 struct group *gr = (struct group *) getgrgid (st->st_gid);
897
898 if (gr)
899 return gr->gr_name;
900 else
901 return NULL;
902#endif
903}
904
6b61353c 905DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 2, 0,
335c5470
PJ
906 doc: /* Return a list of attributes of file FILENAME.
907Value is nil if specified file cannot be opened.
6b61353c
KH
908
909ID-FORMAT specifies the preferred format of attributes uid and gid (see
e42cd1a7
JB
910below) - valid values are 'string and 'integer. The latter is the
911default, but we plan to change that, so you should specify a non-nil value
912for ID-FORMAT if you use the returned uid or gid.
6b61353c
KH
913
914Elements of the attribute list are:
335c5470
PJ
915 0. t for directory, string (name linked to) for symbolic link, or nil.
916 1. Number of links to file.
78e7d1fe
EZ
917 2. File uid as a string or a number. If a string value cannot be
918 looked up, a numeric value, either an integer or a float, is returned.
6b61353c 919 3. File gid, likewise.
335c5470
PJ
920 4. Last access time, as a list of two integers.
921 First integer has high-order 16 bits of time, second has low 16 bits.
e02131a2
EZ
922 (See a note below about access time on FAT-based filesystems.)
923 5. Last modification time, likewise. This is the time of the last
924 change to the file's contents.
925 6. Last status change time, likewise. This is the time of last change
926 to the file's attributes: owner and group, access mode bits, etc.
335c5470
PJ
927 7. Size in bytes.
928 This is a floating point number if the size is too large for an integer.
929 8. File modes, as a string of ten letters or dashes as in ls -l.
e0f24100 930 9. t if file's gid would change if file were deleted and recreated.
e02131a2
EZ
93110. inode number. If inode number is larger than what Emacs integer
932 can hold, but still fits into a 32-bit number, this is a cons cell
933 containing two integers: first the high part, then the low 16 bits.
934 If the inode number is wider than 32 bits, this is of the form
935 (HIGH MIDDLE . LOW): first the high 24 bits, then middle 24 bits,
936 and finally the low 16 bits.
93711. Filesystem device number. If it is larger than what the Emacs
938 integer can hold, this is a cons cell, similar to the inode number.
939
940On most filesystems, the combination of the inode and the device
941number uniquely identifies the file.
6c5665e9
EZ
942
943On MS-Windows, performance depends on `w32-get-true-file-attributes',
21f73755
EZ
944which see.
945
946On some FAT-based filesystems, only the date of last access is recorded,
947so last access time will always be midnight of that day. */)
5842a27b 948 (Lisp_Object filename, Lisp_Object id_format)
14d55bce
RS
949{
950 Lisp_Object values[12];
24c2a54f 951 Lisp_Object encoded;
14d55bce 952 struct stat s;
98601119 953#ifdef BSD4_2
b3edfc9b 954 Lisp_Object dirname;
14d55bce 955 struct stat sdir;
98601119 956#endif /* BSD4_2 */
14d55bce 957 char modes[10];
32f4334d 958 Lisp_Object handler;
7435aef8 959 struct gcpro gcpro1;
51105b13 960 char *uname = NULL, *gname = NULL;
14d55bce
RS
961
962 filename = Fexpand_file_name (filename, Qnil);
32f4334d
RS
963
964 /* If the file name has special constructs in it,
965 call the corresponding file handler. */
a617e913 966 handler = Ffind_file_name_handler (filename, Qfile_attributes);
32f4334d 967 if (!NILP (handler))
6b61353c
KH
968 { /* Only pass the extra arg if it is used to help backward compatibility
969 with old file handlers which do not implement the new arg. --Stef */
970 if (NILP (id_format))
971 return call2 (handler, Qfile_attributes, filename);
972 else
973 return call3 (handler, Qfile_attributes, filename, id_format);
974 }
32f4334d 975
7435aef8 976 GCPRO1 (filename);
24c2a54f 977 encoded = ENCODE_FILE (filename);
7435aef8 978 UNGCPRO;
24c2a54f 979
d5db4077 980 if (lstat (SDATA (encoded), &s) < 0)
14d55bce
RS
981 return Qnil;
982
983 switch (s.st_mode & S_IFMT)
984 {
985 default:
986 values[0] = Qnil; break;
987 case S_IFDIR:
988 values[0] = Qt; break;
989#ifdef S_IFLNK
990 case S_IFLNK:
991 values[0] = Ffile_symlink_p (filename); break;
992#endif
993 }
994 values[1] = make_number (s.st_nlink);
51105b13
EZ
995
996 if (!(NILP (id_format) || EQ (id_format, Qinteger)))
6b61353c 997 {
8c8a7c58 998 BLOCK_INPUT;
8aaaec6b 999 uname = stat_uname (&s);
8aaaec6b 1000 gname = stat_gname (&s);
8c8a7c58 1001 UNBLOCK_INPUT;
6b61353c 1002 }
51105b13 1003 if (uname)
80904120 1004 values[2] = DECODE_SYSTEM (build_string (uname));
51105b13 1005 else
58a12889 1006 values[2] = make_fixnum_or_float (s.st_uid);
51105b13 1007 if (gname)
80904120 1008 values[3] = DECODE_SYSTEM (build_string (gname));
51105b13 1009 else
58a12889 1010 values[3] = make_fixnum_or_float (s.st_gid);
51105b13 1011
14d55bce
RS
1012 values[4] = make_time (s.st_atime);
1013 values[5] = make_time (s.st_mtime);
1014 values[6] = make_time (s.st_ctime);
58a12889 1015 values[7] = make_fixnum_or_float (s.st_size);
4bc12672
JR
1016 /* If the size is negative, and its type is long, convert it back to
1017 positive. */
1018 if (s.st_size < 0 && sizeof (s.st_size) == sizeof (long))
1019 values[7] = make_float ((double) ((unsigned long) s.st_size));
1020
14d55bce
RS
1021 filemodestring (&s, modes);
1022 values[8] = make_string (modes, 10);
98601119 1023#ifdef BSD4_2 /* file gid will be dir gid */
14d55bce 1024 dirname = Ffile_name_directory (filename);
24c2a54f
RS
1025 if (! NILP (dirname))
1026 encoded = ENCODE_FILE (dirname);
d5db4077 1027 if (! NILP (dirname) && stat (SDATA (encoded), &sdir) == 0)
01388a3d 1028 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
14d55bce
RS
1029 else /* if we can't tell, assume worst */
1030 values[9] = Qt;
1031#else /* file gid will be egid */
01388a3d 1032 values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
98601119 1033#endif /* not BSD4_2 */
58a12889 1034 if (!FIXNUM_OVERFLOW_P (s.st_ino))
e058f331 1035 /* Keep the most common cases as integers. */
58a12889
AS
1036 values[10] = make_number (s.st_ino);
1037 else if (!FIXNUM_OVERFLOW_P (s.st_ino >> 16))
4c637faa
RS
1038 /* To allow inode numbers larger than VALBITS, separate the bottom
1039 16 bits. */
e058f331
EZ
1040 values[10] = Fcons (make_number ((EMACS_INT)(s.st_ino >> 16)),
1041 make_number ((EMACS_INT)(s.st_ino & 0xffff)));
4c637faa 1042 else
e058f331
EZ
1043 {
1044 /* To allow inode numbers beyond 32 bits, separate into 2 24-bit
ff8ddc7b 1045 high parts and a 16-bit bottom part.
25ae5671
EZ
1046 The code on the next line avoids a compiler warning on
1047 systems where st_ino is 32 bit wide. (bug#766). */
ff8ddc7b 1048 EMACS_INT high_ino = s.st_ino >> 31 >> 1;
e058f331
EZ
1049 EMACS_INT low_ino = s.st_ino & 0xffffffff;
1050
1051 values[10] = Fcons (make_number (high_ino >> 8),
1052 Fcons (make_number (((high_ino & 0xff) << 16)
1053 + (low_ino >> 16)),
1054 make_number (low_ino & 0xffff)));
1055 }
68c45bf0 1056
58a12889
AS
1057 /* Likewise for device. */
1058 if (FIXNUM_OVERFLOW_P (s.st_dev))
68c45bf0
PE
1059 values[11] = Fcons (make_number (s.st_dev >> 16),
1060 make_number (s.st_dev & 0xffff));
1061 else
1062 values[11] = make_number (s.st_dev);
1063
14d55bce
RS
1064 return Flist (sizeof(values) / sizeof(values[0]), values);
1065}
4424b255
GV
1066
1067DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0,
335c5470
PJ
1068 doc: /* Return t if first arg file attributes list is less than second.
1069Comparison is in lexicographic order and case is significant. */)
5842a27b 1070 (Lisp_Object f1, Lisp_Object f2)
4424b255
GV
1071{
1072 return Fstring_lessp (Fcar (f1), Fcar (f2));
1073}
14d55bce 1074\f
dfcf069d 1075void
971de7fb 1076syms_of_dired (void)
14d55bce 1077{
d67b4f80
DN
1078 Qdirectory_files = intern_c_string ("directory-files");
1079 Qdirectory_files_and_attributes = intern_c_string ("directory-files-and-attributes");
1080 Qfile_name_completion = intern_c_string ("file-name-completion");
1081 Qfile_name_all_completions = intern_c_string ("file-name-all-completions");
1082 Qfile_attributes = intern_c_string ("file-attributes");
1083 Qfile_attributes_lessp = intern_c_string ("file-attributes-lessp");
1084 Qdefault_directory = intern_c_string ("default-directory");
32f4334d 1085
a2d3836c 1086 staticpro (&Qdirectory_files);
4424b255 1087 staticpro (&Qdirectory_files_and_attributes);
a2d3836c
EN
1088 staticpro (&Qfile_name_completion);
1089 staticpro (&Qfile_name_all_completions);
1090 staticpro (&Qfile_attributes);
4424b255 1091 staticpro (&Qfile_attributes_lessp);
01bb4018 1092 staticpro (&Qdefault_directory);
a2d3836c 1093
14d55bce 1094 defsubr (&Sdirectory_files);
4424b255 1095 defsubr (&Sdirectory_files_and_attributes);
14d55bce 1096 defsubr (&Sfile_name_completion);
14d55bce
RS
1097 defsubr (&Sfile_name_all_completions);
1098 defsubr (&Sfile_attributes);
4424b255 1099 defsubr (&Sfile_attributes_lessp);
14d55bce 1100
14d55bce 1101 DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions,
407a52c4
LT
1102 doc: /* Completion ignores file names ending in any string in this list.
1103It does not ignore them if all possible completions end in one of
1104these strings or when displaying a list of completions.
1105It ignores directory names if they match any string in this list which
1106ends in a slash. */);
14d55bce
RS
1107 Vcompletion_ignored_extensions = Qnil;
1108}
6b61353c
KH
1109
1110/* arch-tag: 1ac8deca-4d8f-4d41-ade9-089154d98c03
1111 (do not change this comment) */