(sys_suspend): Read EMACS_PARENT_PID envvar for parent.
[bpt/emacs.git] / src / dired.c
CommitLineData
14d55bce
RS
1/* Lisp functions for making directory listings.
2 Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21#include <stdio.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24
25#include "config.h"
26
27#ifdef SYSV_SYSTEM_DIR
28
29#include <dirent.h>
30#define DIRENTRY struct dirent
31#define NAMLEN(p) strlen (p->d_name)
32
33#else
34
35#ifdef NONSYSTEM_DIR_LIBRARY
36#include "ndir.h"
37#else /* not NONSYSTEM_DIR_LIBRARY */
38#include <sys/dir.h>
39#endif /* not NONSYSTEM_DIR_LIBRARY */
40
41#define DIRENTRY struct direct
42#define NAMLEN(p) p->d_namlen
43
44extern DIR *opendir ();
45extern struct direct *readdir ();
46
47#endif
48
14d55bce
RS
49#include "lisp.h"
50#include "buffer.h"
51#include "commands.h"
52
53#include "regex.h"
14d55bce
RS
54
55#define min(a, b) ((a) < (b) ? (a) : (b))
56
57/* if system does not have symbolic links, it does not have lstat.
58 In that case, use ordinary stat instead. */
59
60#ifndef S_IFLNK
61#define lstat stat
62#endif
63
64Lisp_Object Vcompletion_ignored_extensions;
65
66Lisp_Object Qcompletion_ignore_case;
32f4334d
RS
67
68Lisp_Object Qdirectory_files;
69Lisp_Object Qfile_name_completion;
70Lisp_Object Qfile_name_all_completions;
434e6714 71Lisp_Object Qfile_attributes;
14d55bce
RS
72\f
73DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 4, 0,
74 "Return a list of names of files in DIRECTORY.\n\
75There are three optional arguments:\n\
76If FULL is non-nil, absolute pathnames of the files are returned.\n\
77If MATCH is non-nil, only pathnames containing that regexp are returned.\n\
78If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\
79 NOSORT is useful if you plan to sort the result yourself.")
80 (dirname, full, match, nosort)
81 Lisp_Object dirname, full, match, nosort;
82{
83 DIR *d;
84 int length;
85 Lisp_Object list, name;
32f4334d
RS
86 Lisp_Object handler;
87
88 /* If the file name has special constructs in it,
89 call the corresponding file handler. */
434e6714 90 handler = find_file_handler (dirname);
32f4334d
RS
91 if (!NILP (handler))
92 {
93 Lisp_Object args[6];
94
95 args[0] = handler;
96 args[1] = Qdirectory_files;
97 args[2] = dirname;
98 args[3] = full;
99 args[4] = match;
100 args[5] = nosort;
101 return Ffuncall (6, args);
102 }
14d55bce 103
265a9e55 104 if (!NILP (match))
14d55bce
RS
105 {
106 CHECK_STRING (match, 3);
ebb9e16f
JB
107
108 /* MATCH might be a flawed regular expression. Rather than
109 catching and signalling our own errors, we just call
110 compile_pattern to do the work for us. */
14d55bce 111#ifdef VMS
ebb9e16f 112 compile_pattern (match, &searchbuf, 0
14d55bce
RS
113 buffer_defaults.downcase_table->contents);
114#else
ebb9e16f 115 compile_pattern (match, &searchbuf, 0, 0);
14d55bce
RS
116#endif
117 }
118
119 dirname = Fexpand_file_name (dirname, Qnil);
120 if (!(d = opendir (XSTRING (Fdirectory_file_name (dirname))->data)))
121 report_file_error ("Opening directory", Fcons (dirname, Qnil));
122
123 list = Qnil;
124 length = XSTRING (dirname)->size;
125
126 /* Loop reading blocks */
127 while (1)
128 {
129 DIRENTRY *dp = readdir (d);
130 int len;
131
132 if (!dp) break;
133 len = NAMLEN (dp);
134 if (dp->d_ino)
135 {
265a9e55 136 if (NILP (match)
14d55bce
RS
137 || (0 <= re_search (&searchbuf, dp->d_name, len, 0, len, 0)))
138 {
265a9e55 139 if (!NILP (full))
14d55bce
RS
140 {
141 int index = XSTRING (dirname)->size;
142 int total = len + index;
143#ifndef VMS
144 if (length == 0
145 || XSTRING (dirname)->data[length - 1] != '/')
146 total++;
147#endif /* VMS */
148
149 name = make_uninit_string (total);
150 bcopy (XSTRING (dirname)->data, XSTRING (name)->data,
151 index);
152#ifndef VMS
153 if (length == 0
154 || XSTRING (dirname)->data[length - 1] != '/')
155 XSTRING (name)->data[index++] = '/';
156#endif /* VMS */
157 bcopy (dp->d_name, XSTRING (name)->data + index, len);
158 }
159 else
160 name = make_string (dp->d_name, len);
161 list = Fcons (name, list);
162 }
163 }
164 }
165 closedir (d);
265a9e55 166 if (!NILP (nosort))
14d55bce
RS
167 return list;
168 return Fsort (Fnreverse (list), Qstring_lessp);
169}
170\f
171Lisp_Object file_name_completion ();
172
173DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion,
174 2, 2, 0,
175 "Complete file name FILE in directory DIR.\n\
176Returns the longest string\n\
177common to all filenames in DIR that start with FILE.\n\
178If there is only one and FILE matches it exactly, returns t.\n\
179Returns nil if DIR contains no name starting with FILE.")
180 (file, dirname)
181 Lisp_Object file, dirname;
182{
32f4334d 183 Lisp_Object handler;
14d55bce
RS
184 /* Don't waste time trying to complete a null string.
185 Besides, this case happens when user is being asked for
186 a directory name and has supplied one ending in a /.
187 We would not want to add anything in that case
188 even if there are some unique characters in that directory. */
189 if (XTYPE (file) == Lisp_String && XSTRING (file)->size == 0)
190 return file;
32f4334d
RS
191
192 /* If the file name has special constructs in it,
193 call the corresponding file handler. */
434e6714 194 handler = find_file_handler (dirname);
32f4334d
RS
195 if (!NILP (handler))
196 return call3 (handler, Qfile_name_completion, file, dirname);
197
14d55bce
RS
198 return file_name_completion (file, dirname, 0, 0);
199}
200
201DEFUN ("file-name-all-completions", Ffile_name_all_completions,
202 Sfile_name_all_completions, 2, 2, 0,
203 "Return a list of all completions of file name FILE in directory DIR.\n\
204These are all file names in directory DIR which begin with FILE.")
205 (file, dirname)
206 Lisp_Object file, dirname;
207{
32f4334d
RS
208 Lisp_Object handler;
209
210 /* If the file name has special constructs in it,
211 call the corresponding file handler. */
434e6714 212 handler = find_file_handler (dirname);
32f4334d
RS
213 if (!NILP (handler))
214 return call3 (handler, Qfile_name_all_completions, file, dirname);
215
14d55bce
RS
216 return file_name_completion (file, dirname, 1, 0);
217}
218
219#ifdef VMS
220
221DEFUN ("file-name-all-versions", Ffile_name_all_versions,
222 Sfile_name_all_versions, 2, 2, 0,
223 "Return a list of all versions of file name FILE in directory DIR.")
224 (file, dirname)
225 Lisp_Object file, dirname;
226{
227 return file_name_completion (file, dirname, 1, 1);
228}
229
230#endif /* VMS */
231
232Lisp_Object
233file_name_completion (file, dirname, all_flag, ver_flag)
234 Lisp_Object file, dirname;
235 int all_flag, ver_flag;
236{
237 DIR *d;
238 DIRENTRY *dp;
239 int bestmatchsize, skip;
240 register int compare, matchsize;
241 unsigned char *p1, *p2;
242 int matchcount = 0;
243 Lisp_Object bestmatch, tem, elt, name;
244 struct stat st;
245 int directoryp;
246 int passcount;
247 int count = specpdl_ptr - specpdl;
248#ifdef VMS
249 extern DIRENTRY * readdirver ();
250
251 DIRENTRY *((* readfunc) ());
252
253 /* Filename completion on VMS ignores case, since VMS filesys does. */
254 specbind (Qcompletion_ignore_case, Qt);
255
256 readfunc = readdir;
257 if (ver_flag)
258 readfunc = readdirver;
259 file = Fupcase (file);
260#else /* not VMS */
261 CHECK_STRING (file, 0);
262#endif /* not VMS */
263
264 dirname = Fexpand_file_name (dirname, Qnil);
265 bestmatch = Qnil;
266
267 /* With passcount = 0, ignore files that end in an ignored extension.
268 If nothing found then try again with passcount = 1, don't ignore them.
269 If looking for all completions, start with passcount = 1,
270 so always take even the ignored ones.
271
272 ** It would not actually be helpful to the user to ignore any possible
273 completions when making a list of them.** */
274
265a9e55 275 for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++)
14d55bce
RS
276 {
277 if (!(d = opendir (XSTRING (Fdirectory_file_name (dirname))->data)))
278 report_file_error ("Opening directory", Fcons (dirname, Qnil));
279
280 /* Loop reading blocks */
281 /* (att3b compiler bug requires do a null comparison this way) */
282 while (1)
283 {
284 DIRENTRY *dp;
285 int len;
286
287#ifdef VMS
288 dp = (*readfunc) (d);
289#else
290 dp = readdir (d);
291#endif
292 if (!dp) break;
293
294 len = NAMLEN (dp);
295
265a9e55 296 if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
14d55bce
RS
297 goto quit;
298 if (!dp->d_ino
299 || len < XSTRING (file)->size
300 || 0 <= scmp (dp->d_name, XSTRING (file)->data,
301 XSTRING (file)->size))
302 continue;
303
304 if (file_name_completion_stat (dirname, dp, &st) < 0)
305 continue;
306
307 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
308 tem = Qnil;
309 if (!directoryp)
310 {
311 /* Compare extensions-to-be-ignored against end of this file name */
312 /* if name is not an exact match against specified string */
313 if (!passcount && len > XSTRING (file)->size)
314 /* and exit this for loop if a match is found */
315 for (tem = Vcompletion_ignored_extensions;
316 CONSP (tem); tem = XCONS (tem)->cdr)
317 {
318 elt = XCONS (tem)->car;
319 if (XTYPE (elt) != Lisp_String) continue;
320 skip = len - XSTRING (elt)->size;
321 if (skip < 0) continue;
322
323 if (0 <= scmp (dp->d_name + skip,
324 XSTRING (elt)->data,
325 XSTRING (elt)->size))
326 continue;
327 break;
328 }
329 }
330
331 /* Unless an ignored-extensions match was found,
332 process this name as a completion */
333 if (passcount || !CONSP (tem))
334 {
335 /* Update computation of how much all possible completions match */
336
337 matchcount++;
338
265a9e55 339 if (all_flag || NILP (bestmatch))
14d55bce
RS
340 {
341 /* This is a possible completion */
342 if (directoryp)
343 {
344 /* This completion is a directory; make it end with '/' */
345 name = Ffile_name_as_directory (make_string (dp->d_name, len));
346 }
347 else
348 name = make_string (dp->d_name, len);
349 if (all_flag)
350 {
351 bestmatch = Fcons (name, bestmatch);
352 }
353 else
354 {
355 bestmatch = name;
356 bestmatchsize = XSTRING (name)->size;
357 }
358 }
359 else
360 {
361 compare = min (bestmatchsize, len);
362 p1 = XSTRING (bestmatch)->data;
363 p2 = (unsigned char *) dp->d_name;
364 matchsize = scmp(p1, p2, compare);
365 if (matchsize < 0)
366 matchsize = compare;
367 /* If this dirname all matches,
368 see if implicit following slash does too. */
369 if (directoryp
370 && compare == matchsize
371 && bestmatchsize > matchsize
372 && p1[matchsize] == '/')
373 matchsize++;
374 bestmatchsize = min (matchsize, bestmatchsize);
375 }
376 }
377 }
378 closedir (d);
379 }
380
381 unbind_to (count, Qnil);
382
265a9e55 383 if (all_flag || NILP (bestmatch))
14d55bce
RS
384 return bestmatch;
385 if (matchcount == 1 && bestmatchsize == XSTRING (file)->size)
386 return Qt;
387 return Fsubstring (bestmatch, make_number (0), make_number (bestmatchsize));
388 quit:
389 if (d) closedir (d);
390 Vquit_flag = Qnil;
391 return Fsignal (Qquit, Qnil);
392}
393
394file_name_completion_stat (dirname, dp, st_addr)
395 Lisp_Object dirname;
396 DIRENTRY *dp;
397 struct stat *st_addr;
398{
399 int len = NAMLEN (dp);
400 int pos = XSTRING (dirname)->size;
401 char *fullname = (char *) alloca (len + pos + 2);
402
403 bcopy (XSTRING (dirname)->data, fullname, pos);
404#ifndef VMS
405 if (fullname[pos - 1] != '/')
406 fullname[pos++] = '/';
407#endif
408
409 bcopy (dp->d_name, fullname + pos, len);
410 fullname[pos + len] = 0;
411
412 return stat (fullname, st_addr);
413}
414\f
415Lisp_Object
416make_time (time)
417 int time;
418{
419 return Fcons (make_number (time >> 16),
420 Fcons (make_number (time & 0177777), Qnil));
421}
422
423DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 1, 0,
424 "Return a list of attributes of file FILENAME.\n\
425Value is nil if specified file cannot be opened.\n\
426Otherwise, list elements are:\n\
427 0. t for directory, string (name linked to) for symbolic link, or nil.\n\
428 1. Number of links to file.\n\
429 2. File uid.\n\
430 3. File gid.\n\
431 4. Last access time, as a list of two integers.\n\
432 First integer has high-order 16 bits of time, second has low 16 bits.\n\
433 5. Last modification time, likewise.\n\
434 6. Last status change time, likewise.\n\
435 7. Size in bytes.\n\
436 8. File modes, as a string of ten letters or dashes as in ls -l.\n\
437 9. t iff file's gid would change if file were deleted and recreated.\n\
43810. inode number.\n\
43911. Device number.\n\
440\n\
441If file does not exists, returns nil.")
442 (filename)
443 Lisp_Object filename;
444{
445 Lisp_Object values[12];
446 Lisp_Object dirname;
447 struct stat s;
448 struct stat sdir;
449 char modes[10];
32f4334d 450 Lisp_Object handler;
14d55bce
RS
451
452 filename = Fexpand_file_name (filename, Qnil);
32f4334d
RS
453
454 /* If the file name has special constructs in it,
455 call the corresponding file handler. */
456 handler = find_file_handler (filename);
457 if (!NILP (handler))
458 return call2 (handler, Qfile_attributes, filename);
459
14d55bce
RS
460 if (lstat (XSTRING (filename)->data, &s) < 0)
461 return Qnil;
462
463 switch (s.st_mode & S_IFMT)
464 {
465 default:
466 values[0] = Qnil; break;
467 case S_IFDIR:
468 values[0] = Qt; break;
469#ifdef S_IFLNK
470 case S_IFLNK:
471 values[0] = Ffile_symlink_p (filename); break;
472#endif
473 }
474 values[1] = make_number (s.st_nlink);
475 values[2] = make_number (s.st_uid);
476 values[3] = make_number (s.st_gid);
477 values[4] = make_time (s.st_atime);
478 values[5] = make_time (s.st_mtime);
479 values[6] = make_time (s.st_ctime);
480 /* perhaps we should set this to most-positive-fixnum if it is too large? */
481 values[7] = make_number (s.st_size);
482 filemodestring (&s, modes);
483 values[8] = make_string (modes, 10);
484#ifdef BSD4_3 /* Gross kludge to avoid lack of "#if defined(...)" in VMS */
485#define BSD4_2 /* A new meaning to the term `backwards compatability' */
486#endif
487#ifdef BSD4_2 /* file gid will be dir gid */
488 dirname = Ffile_name_directory (filename);
489 if (dirname != Qnil && stat (XSTRING (dirname)->data, &sdir) == 0)
490 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
491 else /* if we can't tell, assume worst */
492 values[9] = Qt;
493#else /* file gid will be egid */
494 values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
495#endif /* BSD4_2 (or BSD4_3) */
496#ifdef BSD4_3
497#undef BSD4_2 /* ok, you can look again without throwing up */
498#endif
499 values[10] = make_number (s.st_ino);
500 values[11] = make_number (s.st_dev);
501 return Flist (sizeof(values) / sizeof(values[0]), values);
502}
503\f
504syms_of_dired ()
505{
32f4334d
RS
506 Qdirectory_files = intern ("directory-files");
507 Qfile_name_completion = intern ("file-name-completion");
508 Qfile_name_all_completions = intern ("file-name-all-completions");
434e6714 509 Qfile_attributes = intern ("file-attributes");
32f4334d 510
14d55bce
RS
511 defsubr (&Sdirectory_files);
512 defsubr (&Sfile_name_completion);
513#ifdef VMS
514 defsubr (&Sfile_name_all_versions);
515#endif /* VMS */
516 defsubr (&Sfile_name_all_completions);
517 defsubr (&Sfile_attributes);
518
519#ifdef VMS
520 Qcompletion_ignore_case = intern ("completion-ignore-case");
521 staticpro (&Qcompletion_ignore_case);
522#endif /* VMS */
523
524 DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions,
525 "*Completion ignores filenames ending in any string in this list.\n\
526This variable does not affect lists of possible completions,\n\
527but does affect the commands that actually do completions.");
528 Vcompletion_ignored_extensions = Qnil;
529}