1 /* $Id: files.c 4520 2010-11-12 06:23:14Z astyanax $ */
2 /**************************************************************************
5 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
6 * 2008, 2009 Free Software Foundation, Inc. *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 3, or (at your option) *
10 * any later version. *
12 * This program is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15 * General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
22 **************************************************************************/
35 /* Add an entry to the openfile openfilestruct. This should only be
36 * called from open_buffer(). */
37 void make_new_buffer(void)
39 /* If there are no entries in openfile, make the first one and
41 if (openfile
== NULL
) {
42 openfile
= make_new_opennode();
43 splice_opennode(openfile
, openfile
, openfile
);
44 /* Otherwise, make a new entry for openfile, splice it in after
45 * the current entry, and move to it. */
47 splice_opennode(openfile
, make_new_opennode(), openfile
->next
);
48 openfile
= openfile
->next
;
51 /* Initialize the new buffer. */
55 /* Initialize the current entry of the openfile openfilestruct. */
56 void initialize_buffer(void)
58 assert(openfile
!= NULL
);
60 openfile
->filename
= mallocstrcpy(NULL
, "");
62 initialize_buffer_text();
64 openfile
->current_x
= 0;
65 openfile
->placewewant
= 0;
66 openfile
->current_y
= 0;
68 openfile
->modified
= FALSE
;
70 openfile
->mark_set
= FALSE
;
72 openfile
->mark_begin
= NULL
;
73 openfile
->mark_begin_x
= 0;
75 openfile
->fmt
= NIX_FILE
;
77 openfile
->current_stat
= NULL
;
78 openfile
->undotop
= NULL
;
79 openfile
->current_undo
= NULL
;
82 openfile
->colorstrings
= NULL
;
86 /* Initialize the text of the current entry of the openfile
88 void initialize_buffer_text(void)
90 assert(openfile
!= NULL
);
92 openfile
->fileage
= make_new_node(NULL
);
93 openfile
->fileage
->data
= mallocstrcpy(NULL
, "");
95 openfile
->filebot
= openfile
->fileage
;
96 openfile
->edittop
= openfile
->fileage
;
97 openfile
->current
= openfile
->fileage
;
100 openfile
->fileage
->multidata
= NULL
;
103 openfile
->totsize
= 0;
106 /* If it's not "", filename is a file to open. We make a new buffer, if
107 * necessary, and then open and read the file, if applicable. */
108 void open_buffer(const char *filename
, bool undoable
)
110 bool new_buffer
= (openfile
== NULL
111 #ifdef ENABLE_MULTIBUFFER
112 || ISSET(MULTIBUFFER
)
115 /* Whether we load into this buffer or a new one. */
118 /* rc == -2 means that we have a new file. -1 means that the
119 * open() failed. 0 means that the open() succeeded. */
121 assert(filename
!= NULL
);
123 #ifndef DISABLE_OPERATINGDIR
124 if (check_operating_dir(filename
, FALSE
)) {
125 statusbar(_("Can't insert file from outside of %s"),
131 /* If the filename isn't blank, open the file. Otherwise, treat it
133 rc
= (filename
[0] != '\0') ? open_file(filename
, new_buffer
, &f
) :
136 /* If we're loading into a new buffer, add a new entry to
141 /* If we have a file, and we're loading into a new buffer, update
143 if (rc
!= -1 && new_buffer
)
144 openfile
->filename
= mallocstrcpy(openfile
->filename
, filename
);
146 /* If we have a non-new file, read it in. Then, if the buffer has
147 * no stat, update the stat, if applicable. */
149 read_file(f
, rc
, filename
, undoable
, new_buffer
);
151 if (openfile
->current_stat
== NULL
) {
152 openfile
->current_stat
=
153 (struct stat
*)nmalloc(sizeof(struct stat
));
154 stat(filename
, openfile
->current_stat
);
159 /* If we have a file, and we're loading into a new buffer, move back
160 * to the beginning of the first line of the buffer. */
161 if (rc
!= -1 && new_buffer
) {
162 openfile
->current
= openfile
->fileage
;
163 openfile
->current_x
= 0;
164 openfile
->placewewant
= 0;
168 /* If we're loading into a new buffer, update the colors to account
169 * for it, if applicable. */
175 #ifndef DISABLE_SPELLER
176 /* If it's not "", filename is a file to open. We blow away the text of
177 * the current buffer, and then open and read the file, if
178 * applicable. Note that we skip the operating directory test when
180 void replace_buffer(const char *filename
)
184 /* rc == -2 means that we have a new file. -1 means that the
185 * open() failed. 0 means that the open() succeeded. */
187 assert(filename
!= NULL
);
189 /* If the filename isn't blank, open the file. Otherwise, treat it
191 rc
= (filename
[0] != '\0') ? open_file(filename
, TRUE
, &f
) : -2;
193 /* Reinitialize the text of the current buffer. */
194 free_filestruct(openfile
->fileage
);
195 initialize_buffer_text();
197 /* If we have a non-new file, read it in. */
199 read_file(f
, rc
, filename
, FALSE
, TRUE
);
201 /* Move back to the beginning of the first line of the buffer. */
202 openfile
->current
= openfile
->fileage
;
203 openfile
->current_x
= 0;
204 openfile
->placewewant
= 0;
206 #endif /* !DISABLE_SPELLER */
208 /* Update the screen to account for the current buffer. */
209 void display_buffer(void)
211 /* Update the titlebar, since the filename may have changed. */
215 /* Make sure we're using the buffer's associated colors, if
220 /* Update the edit window. */
224 #ifdef ENABLE_MULTIBUFFER
225 /* Switch to the next file buffer if next_buf is TRUE. Otherwise,
226 * switch to the previous file buffer. */
227 void switch_to_prevnext_buffer(bool next_buf
)
229 assert(openfile
!= NULL
);
231 /* If only one file buffer is open, indicate it on the statusbar and
233 if (openfile
== openfile
->next
) {
234 statusbar(_("No more open file buffers"));
238 /* Switch to the next or previous file buffer, depending on the
239 * value of next_buf. */
240 openfile
= next_buf
? openfile
->next
: openfile
->prev
;
243 fprintf(stderr
, "filename is %s\n", openfile
->filename
);
246 /* Update the screen to account for the current buffer. */
249 /* Indicate the switch on the statusbar. */
250 statusbar(_("Switched to %s"),
251 ((openfile
->filename
[0] == '\0') ? _("New Buffer") :
252 openfile
->filename
));
255 dump_filestruct(openfile
->current
);
259 /* Switch to the previous entry in the openfile filebuffer. */
260 void switch_to_prev_buffer_void(void)
262 switch_to_prevnext_buffer(FALSE
);
265 /* Switch to the next entry in the openfile filebuffer. */
266 void switch_to_next_buffer_void(void)
268 switch_to_prevnext_buffer(TRUE
);
271 /* Delete an entry from the openfile filebuffer, and switch to the one
272 * after it. Return TRUE on success, or FALSE if there are no more open
274 bool close_buffer(void)
276 assert(openfile
!= NULL
);
278 /* If only one file buffer is open, get out. */
279 if (openfile
== openfile
->next
)
282 /* Switch to the next file buffer. */
283 switch_to_next_buffer_void();
285 /* Close the file buffer we had open before. */
286 unlink_opennode(openfile
->prev
);
292 #endif /* ENABLE_MULTIBUFFER */
294 /* A bit of a copy and paste from open_file(), is_file_writable()
295 * just checks whether the file is appendable as a quick
296 * permissions check, and we tend to err on the side of permissiveness
297 * (reporting TRUE when it might be wrong) to not fluster users
298 * editing on odd filesystems by printing incorrect warnings.
300 int is_file_writable(const char *filename
)
302 struct stat fileinfo
, fileinfo2
;
309 if (ISSET(VIEW_MODE
))
312 assert(filename
!= NULL
);
314 /* Get the specified file's full path. */
315 full_filename
= get_full_path(filename
);
317 /* Okay, if we can't stat the path due to a component's
318 permissions, just try the relative one */
319 if (full_filename
== NULL
320 || (stat(full_filename
, &fileinfo
) == -1 && stat(filename
, &fileinfo2
) != -1))
321 full_filename
= mallocstrcpy(NULL
, filename
);
323 if ((fd
= open(full_filename
, O_WRONLY
| O_CREAT
| O_APPEND
, S_IRUSR
|
324 S_IWUSR
| S_IRGRP
| S_IWGRP
| S_IROTH
| S_IWOTH
)) == -1
325 || (f
= fdopen(fd
, "a")) == NULL
)
335 /* We make a new line of text from buf. buf is length buf_len. If
336 * first_line_ins is TRUE, then we put the new line at the top of the
337 * file. Otherwise, we assume prevnode is the last line of the file,
338 * and put our line after prevnode. */
339 filestruct
*read_line(char *buf
, filestruct
*prevnode
, bool
340 *first_line_ins
, size_t buf_len
)
342 filestruct
*fileptr
= (filestruct
*)nmalloc(sizeof(filestruct
));
344 /* Convert nulls to newlines. buf_len is the string's real
346 unsunder(buf
, buf_len
);
348 assert(openfile
->fileage
!= NULL
&& strlen(buf
) == buf_len
);
350 fileptr
->data
= mallocstrcpy(NULL
, buf
);
353 /* If it's a DOS file ("\r\n"), and file conversion isn't disabled,
354 * strip the '\r' part from fileptr->data. */
355 if (!ISSET(NO_CONVERT
) && buf_len
> 0 && buf
[buf_len
- 1] == '\r')
356 fileptr
->data
[buf_len
- 1] = '\0';
360 fileptr
->multidata
= NULL
;
363 if (*first_line_ins
) {
364 /* Special case: We're inserting with the cursor on the first
366 fileptr
->prev
= NULL
;
367 fileptr
->next
= openfile
->fileage
;
369 if (*first_line_ins
) {
370 *first_line_ins
= FALSE
;
371 /* If we're inserting into the first line of the file, then
372 * we want to make sure that our edit buffer stays on the
373 * first line and that fileage stays up to date. */
374 openfile
->edittop
= fileptr
;
376 openfile
->filebot
= fileptr
;
377 openfile
->fileage
= fileptr
;
379 assert(prevnode
!= NULL
);
381 fileptr
->prev
= prevnode
;
382 fileptr
->next
= NULL
;
383 fileptr
->lineno
= prevnode
->lineno
+ 1;
384 prevnode
->next
= fileptr
;
390 /* Read an open file into the current buffer. f should be set to the
391 * open file, and filename should be set to the name of the file.
392 * undoable means do we want to create undo records to try and undo this.
393 * Will also attempt to check file writability if fd > 0 and checkwritable == TRUE
395 void read_file(FILE *f
, int fd
, const char *filename
, bool undoable
, bool checkwritable
)
397 size_t num_lines
= 0;
398 /* The number of lines in the file. */
400 /* The length of the current line of the file. */
402 /* The position in the current line of the file. */
403 size_t bufx
= MAX_BUF_SIZE
;
404 /* The size of each chunk of the file that we read. */
406 /* The current input character. */
408 /* The buffer where we store chunks of the file. */
409 filestruct
*fileptr
= openfile
->current
;
410 /* The current line of the file. */
411 bool first_line_ins
= FALSE
;
412 /* Whether we're inserting with the cursor on the first line. */
414 /* The current value we read from the file, whether an input
415 * character or EOF. */
416 bool writable
= TRUE
;
417 /* Is the file writable (if we care) */
420 /* 0 = *nix, 1 = DOS, 2 = Mac, 3 = both DOS and Mac. */
423 assert(openfile
->fileage
!= NULL
&& openfile
->current
!= NULL
);
425 buf
= charalloc(bufx
);
433 if (openfile
->current
== openfile
->fileage
)
434 first_line_ins
= TRUE
;
436 fileptr
= openfile
->current
->prev
;
438 /* Read the entire file into the filestruct. */
439 while ((input_int
= getc(f
)) != EOF
) {
440 input
= (char)input_int
;
442 /* If it's a *nix file ("\n") or a DOS file ("\r\n"), and file
443 * conversion isn't disabled, handle it! */
446 /* If it's a DOS file or a DOS/Mac file ('\r' before '\n' on
447 * the first line if we think it's a *nix file, or on any
448 * line otherwise), and file conversion isn't disabled,
450 if (!ISSET(NO_CONVERT
) && (num_lines
== 0 || format
!= 0) &&
451 i
> 0 && buf
[i
- 1] == '\r') {
452 if (format
== 0 || format
== 2)
457 /* Read in the line properly. */
458 fileptr
= read_line(buf
, fileptr
, &first_line_ins
, len
);
460 /* Reset the line length in preparation for the next
468 /* If it's a Mac file ('\r' without '\n' on the first line if we
469 * think it's a *nix file, or on any line otherwise), and file
470 * conversion isn't disabled, handle it! */
471 } else if (!ISSET(NO_CONVERT
) && (num_lines
== 0 ||
472 format
!= 0) && i
> 0 && buf
[i
- 1] == '\r') {
473 /* If we currently think the file is a *nix file, set format
474 * to Mac. If we currently think the file is a DOS file,
475 * set format to both DOS and Mac. */
476 if (format
== 0 || format
== 1)
479 /* Read in the line properly. */
480 fileptr
= read_line(buf
, fileptr
, &first_line_ins
, len
);
482 /* Reset the line length in preparation for the next line.
483 * Since we've already read in the next character, reset it
484 * to 1 instead of 0. */
493 /* Calculate the total length of the line. It might have
494 * nulls in it, so we can't just use strlen() here. */
497 /* Now we allocate a bigger buffer MAX_BUF_SIZE characters
498 * at a time. If we allocate a lot of space for one line,
499 * we may indeed have to use a buffer this big later on, so
500 * we don't decrease it at all. We do free it at the end,
503 bufx
+= MAX_BUF_SIZE
;
504 buf
= charealloc(buf
, bufx
);
513 /* Perhaps this could use some better handling. */
517 if (fd
> 0 && checkwritable
) {
519 writable
= is_file_writable(filename
);
523 /* If file conversion isn't disabled and the last character in this
524 * file is '\r', read it in properly as a Mac format line. */
525 if (len
== 0 && !ISSET(NO_CONVERT
) && input
== '\r') {
533 /* Did we not get a newline and still have stuff to do? */
536 /* If file conversion isn't disabled and the last character in
537 * this file is '\r', set format to Mac if we currently think
538 * the file is a *nix file, or to both DOS and Mac if we
539 * currently think the file is a DOS file. */
540 if (!ISSET(NO_CONVERT
) && buf
[len
- 1] == '\r' &&
541 (format
== 0 || format
== 1))
545 /* Read in the last line properly. */
546 fileptr
= read_line(buf
, fileptr
, &first_line_ins
, len
);
552 /* If we didn't get a file and we don't already have one, open a
555 open_buffer("", FALSE
);
557 /* Attach the file we got to the filestruct. If we got a file of
558 * zero bytes, don't do anything. */
560 /* If the file we got doesn't end in a newline, tack its last
561 * line onto the beginning of the line at current. */
563 size_t current_len
= strlen(openfile
->current
->data
);
565 /* Adjust the current x-coordinate to compensate for the
566 * change in the current line. */
568 openfile
->current_x
+= len
;
570 openfile
->current_x
= len
;
572 /* Tack the text at fileptr onto the beginning of the text
574 openfile
->current
->data
=
575 charealloc(openfile
->current
->data
, len
+
577 charmove(openfile
->current
->data
+ len
,
578 openfile
->current
->data
, current_len
+ 1);
579 strncpy(openfile
->current
->data
, fileptr
->data
, len
);
581 /* Don't destroy fileage, edittop, or filebot! */
582 if (fileptr
== openfile
->fileage
)
583 openfile
->fileage
= openfile
->current
;
584 if (fileptr
== openfile
->edittop
)
585 openfile
->edittop
= openfile
->current
;
586 if (fileptr
== openfile
->filebot
)
587 openfile
->filebot
= openfile
->current
;
589 /* Move fileptr back one line and blow away the old fileptr,
590 * since its text has been saved. */
591 fileptr
= fileptr
->prev
;
592 if (fileptr
!= NULL
) {
593 if (fileptr
->next
!= NULL
)
598 /* Attach the line at current after the line at fileptr. */
599 if (fileptr
!= NULL
) {
600 fileptr
->next
= openfile
->current
;
601 openfile
->current
->prev
= fileptr
;
604 /* Renumber starting with the last line of the file we
606 renumber(openfile
->current
);
609 openfile
->totsize
+= get_totsize(openfile
->fileage
,
612 /* If the NO_NEWLINES flag isn't set, and text has been added to
613 * the magicline (i.e. a file that doesn't end in a newline has been
614 * inserted at the end of the current buffer), add a new magicline,
615 * and move the current line down to it. */
616 if (!ISSET(NO_NEWLINES
) && openfile
->filebot
->data
[0] != '\0') {
618 openfile
->current
= openfile
->filebot
;
619 openfile
->current_x
= 0;
622 /* Set the current place we want to the end of the last line of the
623 * file we inserted. */
624 openfile
->placewewant
= xplustabs();
633 P_("Read %lu line (Converted from DOS and Mac format)",
634 "Read %lu lines (Converted from DOS and Mac format)",
635 (unsigned long)num_lines
), (unsigned long)num_lines
);
638 P_("Read %lu line (Converted from DOS and Mac format - Warning: No write permission)",
639 "Read %lu lines (Converted from DOS and Mac format - Warning: No write permission)",
640 (unsigned long)num_lines
), (unsigned long)num_lines
);
641 } else if (format
== 2) {
642 openfile
->fmt
= MAC_FILE
;
644 statusbar(P_("Read %lu line (Converted from Mac format)",
645 "Read %lu lines (Converted from Mac format)",
646 (unsigned long)num_lines
), (unsigned long)num_lines
);
648 statusbar(P_("Read %lu line (Converted from Mac format - Warning: No write permission)",
649 "Read %lu lines (Converted from Mac format - Warning: No write permission)",
650 (unsigned long)num_lines
), (unsigned long)num_lines
);
651 } else if (format
== 1) {
652 openfile
->fmt
= DOS_FILE
;
654 statusbar(P_("Read %lu line (Converted from DOS format)",
655 "Read %lu lines (Converted from DOS format)",
656 (unsigned long)num_lines
), (unsigned long)num_lines
);
658 statusbar(P_("Read %lu line (Converted from DOS format - Warning: No write permission)",
659 "Read %lu lines (Converted from DOS format - Warning: No write permission)",
660 (unsigned long)num_lines
), (unsigned long)num_lines
);
664 statusbar(P_("Read %lu line", "Read %lu lines",
665 (unsigned long)num_lines
), (unsigned long)num_lines
);
667 statusbar(P_("Read %lu line ( Warning: No write permission)",
668 "Read %lu lines (Warning: No write permission)",
669 (unsigned long)num_lines
), (unsigned long)num_lines
);
672 /* Open the file (and decide if it exists). If newfie is TRUE, display
673 * "New File" if the file is missing. Otherwise, say "[filename] not
676 * Return -2 if we say "New File", -1 if the file isn't opened, and the
677 * fd opened otherwise. The file might still have an error while reading
678 * with a 0 return value. *f is set to the opened file. */
679 int open_file(const char *filename
, bool newfie
, FILE **f
)
681 struct stat fileinfo
, fileinfo2
;
685 assert(filename
!= NULL
&& f
!= NULL
);
687 /* Get the specified file's full path. */
688 full_filename
= get_full_path(filename
);
690 /* Okay, if we can't stat the path due to a component's
691 permissions, just try the relative one */
692 if (full_filename
== NULL
693 || (stat(full_filename
, &fileinfo
) == -1 && stat(filename
, &fileinfo2
) != -1))
694 full_filename
= mallocstrcpy(NULL
, filename
);
696 if (stat(full_filename
, &fileinfo
) == -1) {
697 /* Well, maybe we can open the file even if the OS
698 says its not there */
699 if ((fd
= open(filename
, O_RDONLY
)) != -1) {
700 statusbar(_("Reading File"));
706 statusbar(_("New File"));
709 statusbar(_("\"%s\" not found"), filename
);
712 } else if (S_ISDIR(fileinfo
.st_mode
) || S_ISCHR(fileinfo
.st_mode
) ||
713 S_ISBLK(fileinfo
.st_mode
)) {
714 /* Don't open directories, character files, or block files.
715 * Sorry, /dev/sndstat! */
716 statusbar(S_ISDIR(fileinfo
.st_mode
) ?
717 _("\"%s\" is a directory") :
718 _("\"%s\" is a device file"), filename
);
721 } else if ((fd
= open(full_filename
, O_RDONLY
)) == -1) {
722 statusbar(_("Error reading %s: %s"), filename
,
727 /* The file is A-OK. Open it. */
728 *f
= fdopen(fd
, "rb");
731 statusbar(_("Error reading %s: %s"), filename
,
736 statusbar(_("Reading File"));
744 /* This function will return the name of the first available extension
745 * of a filename (starting with [name][suffix], then [name][suffix].1,
746 * etc.). Memory is allocated for the return value. If no writable
747 * extension exists, we return "". */
748 char *get_next_filename(const char *name
, const char *suffix
)
750 static int ulmax_digits
= -1;
753 size_t namelen
, suffixlen
;
755 assert(name
!= NULL
&& suffix
!= NULL
);
757 if (ulmax_digits
== -1)
758 ulmax_digits
= digits(ULONG_MAX
);
760 namelen
= strlen(name
);
761 suffixlen
= strlen(suffix
);
763 buf
= charalloc(namelen
+ suffixlen
+ ulmax_digits
+ 2);
764 sprintf(buf
, "%s%s", name
, suffix
);
769 if (stat(buf
, &fs
) == -1)
775 sprintf(buf
+ namelen
+ suffixlen
, ".%lu", i
);
778 /* We get here only if there is no possible save file. Blank out
779 * the filename to indicate this. */
785 /* Insert a file into a new buffer if the MULTIBUFFER flag is set, or
786 * into the current buffer if it isn't. If execute is TRUE, insert the
787 * output of an executed command instead of a file. */
798 char *ans
= mallocstrcpy(NULL
, "");
799 /* The last answer the user typed at the statusbar prompt. */
800 filestruct
*edittop_save
= openfile
->edittop
;
801 size_t current_x_save
= openfile
->current_x
;
802 ssize_t current_y_save
= openfile
->current_y
;
803 bool edittop_inside
= FALSE
, meta_key
= FALSE
, func_key
= FALSE
;
806 bool right_side_up
= FALSE
, single_line
= FALSE
;
809 currmenu
= MINSERTFILE
;
815 #ifdef ENABLE_MULTIBUFFER
817 _("Command to execute in new buffer [from %s] ") :
819 _("Command to execute [from %s] ");
823 #ifdef ENABLE_MULTIBUFFER
825 _("File to insert into new buffer [from %s] ") :
827 _("File to insert [from %s] ");
833 #ifndef DISABLE_TABCOMP
840 &meta_key
, &func_key
,
845 #ifndef DISABLE_OPERATINGDIR
846 operating_dir
!= NULL
&& strcmp(operating_dir
,
847 ".") != 0 ? operating_dir
:
851 /* If we're in multibuffer mode and the filename or command is
852 * blank, open a new buffer instead of canceling. If the
853 * filename or command begins with a newline (i.e. an encoded
854 * null), treat it as though it's blank. */
855 if (i
== -1 || ((i
== -2 || *answer
== '\n')
856 #ifdef ENABLE_MULTIBUFFER
857 && !ISSET(MULTIBUFFER
)
860 statusbar(_("Cancelled"));
863 size_t pww_save
= openfile
->placewewant
;
865 ans
= mallocstrcpy(ans
, answer
);
867 s
= get_shortcut(currmenu
, &i
, &meta_key
, &func_key
);
870 #ifdef ENABLE_MULTIBUFFER
872 if (s
&& s
->scfunc
== NEW_BUFFER_MSG
) {
873 /* Don't allow toggling if we're in view mode. */
874 if (!ISSET(VIEW_MODE
))
879 if (s
&& s
->scfunc
== EXT_CMD_MSG
) {
883 #ifndef DISABLE_BROWSER
886 #endif /* !NANO_TINY */
888 #ifndef DISABLE_BROWSER
889 if (s
&& s
->scfunc
== TO_FILES_MSG
) {
890 char *tmp
= do_browse_from(answer
);
895 /* We have a file now. Indicate this. */
903 /* If we don't have a file yet, go back to the statusbar
906 #ifdef ENABLE_MULTIBUFFER
907 && (i
!= -2 || !ISSET(MULTIBUFFER
))
913 /* Keep track of whether the mark begins inside the
914 * partition and will need adjustment. */
915 if (openfile
->mark_set
) {
916 filestruct
*top
, *bot
;
919 mark_order((const filestruct
**)&top
, &top_x
,
920 (const filestruct
**)&bot
, &bot_x
,
923 single_line
= (top
== bot
);
927 #ifdef ENABLE_MULTIBUFFER
928 if (!ISSET(MULTIBUFFER
)) {
930 /* If we're not inserting into a new buffer, partition
931 * the filestruct so that it contains no text and hence
932 * looks like a new buffer, and keep track of whether
933 * the top of the edit window is inside the
935 filepart
= partition_filestruct(openfile
->current
,
936 openfile
->current_x
, openfile
->current
,
937 openfile
->current_x
);
939 (openfile
->edittop
== openfile
->fileage
);
940 #ifdef ENABLE_MULTIBUFFER
944 /* Convert newlines to nulls, just before we insert the file
945 * or execute the command. */
951 #ifdef ENABLE_MULTIBUFFER
952 if (ISSET(MULTIBUFFER
))
953 /* Open a blank buffer. */
954 open_buffer("", FALSE
);
957 /* Save the command's output in the current buffer. */
958 execute_command(answer
);
960 #ifdef ENABLE_MULTIBUFFER
961 if (ISSET(MULTIBUFFER
)) {
962 /* Move back to the beginning of the first line of
964 openfile
->current
= openfile
->fileage
;
965 openfile
->current_x
= 0;
966 openfile
->placewewant
= 0;
970 #endif /* !NANO_TINY */
971 /* Make sure the path to the file specified in answer is
973 answer
= mallocstrassn(answer
,
974 real_dir_from_tilde(answer
));
976 /* Save the file specified in answer in the current
978 open_buffer(answer
, TRUE
);
983 #ifdef ENABLE_MULTIBUFFER
984 if (ISSET(MULTIBUFFER
))
985 /* Update the screen to account for the current
991 filestruct
*top_save
= openfile
->fileage
;
993 /* If we were at the top of the edit window before, set
994 * the saved value of edittop to the new top of the edit
997 edittop_save
= openfile
->fileage
;
999 /* Update the current x-coordinate to account for the
1000 * number of characters inserted on the current line.
1001 * If the mark begins inside the partition, adjust the
1002 * mark coordinates to compensate for the change in the
1004 openfile
->current_x
= strlen(openfile
->filebot
->data
);
1005 if (openfile
->fileage
== openfile
->filebot
) {
1007 if (openfile
->mark_set
) {
1008 openfile
->mark_begin
= openfile
->current
;
1010 openfile
->mark_begin_x
+=
1011 openfile
->current_x
;
1014 openfile
->current_x
+= current_x_save
;
1017 else if (openfile
->mark_set
) {
1018 if (!right_side_up
) {
1020 openfile
->mark_begin
= openfile
->current
;
1021 openfile
->mark_begin_x
-= current_x_save
;
1023 openfile
->mark_begin_x
-=
1024 openfile
->current_x
;
1029 /* Update the current y-coordinate to account for the
1030 * number of lines inserted. */
1031 openfile
->current_y
+= current_y_save
;
1033 /* Unpartition the filestruct so that it contains all
1034 * the text again. Note that we've replaced the
1035 * non-text originally in the partition with the text in
1036 * the inserted file/executed command output. */
1037 unpartition_filestruct(&filepart
);
1039 /* Renumber starting with the beginning line of the old
1043 /* Restore the old edittop. */
1044 openfile
->edittop
= edittop_save
;
1046 /* Restore the old place we want. */
1047 openfile
->placewewant
= pww_save
;
1049 /* Mark the file as modified. */
1052 /* Update the screen. */
1059 shortcut_init(FALSE
);
1064 /* Insert a file into a new buffer or the current buffer, depending on
1065 * whether the MULTIBUFFER flag is set. If we're in view mode, only
1066 * allow inserting a file into a new buffer. */
1067 void do_insertfile_void(void)
1070 if (ISSET(RESTRICTED
)) {
1071 nano_disabled_msg();
1075 #ifdef ENABLE_MULTIBUFFER
1076 if (ISSET(VIEW_MODE
) && !ISSET(MULTIBUFFER
))
1077 statusbar(_("Key invalid in non-multibuffer mode"));
1086 display_main_list();
1089 /* When passed "[relative path]" or "[relative path][filename]" in
1090 * origpath, return "[full path]" or "[full path][filename]" on success,
1091 * or NULL on error. Do this if the file doesn't exist but the relative
1092 * path does, since the file could exist in memory but not yet on disk).
1093 * Don't do this if the relative path doesn't exist, since we won't be
1094 * able to go there. */
1095 char *get_full_path(const char *origpath
)
1097 struct stat fileinfo
;
1098 char *d_here
, *d_there
, *d_there_file
= NULL
;
1099 const char *last_slash
;
1102 if (origpath
== NULL
)
1105 /* Get the current directory. If it doesn't exist, back up and try
1106 * again until we get a directory that does, and use that as the
1107 * current directory. */
1108 d_here
= charalloc(PATH_MAX
+ 1);
1109 d_here
= getcwd(d_here
, PATH_MAX
+ 1);
1111 while (d_here
== NULL
) {
1112 if (chdir("..") == -1)
1115 d_here
= getcwd(d_here
, PATH_MAX
+ 1);
1118 /* If we succeeded, canonicalize it in d_here. */
1119 if (d_here
!= NULL
) {
1122 /* If the current directory isn't "/", tack a slash onto the end
1124 if (strcmp(d_here
, "/") != 0) {
1125 d_here
= charealloc(d_here
, strlen(d_here
) + 2);
1126 strcat(d_here
, "/");
1128 /* Otherwise, set d_here to "". */
1130 d_here
= mallocstrcpy(NULL
, "");
1132 d_there
= real_dir_from_tilde(origpath
);
1134 /* If stat()ing d_there fails, assume that d_there refers to a new
1135 * file that hasn't been saved to disk yet. Set path_only to TRUE
1136 * if d_there refers to a directory, and FALSE otherwise. */
1137 path_only
= (stat(d_there
, &fileinfo
) != -1 &&
1138 S_ISDIR(fileinfo
.st_mode
));
1140 /* If path_only is TRUE, make sure d_there ends in a slash. */
1142 size_t d_there_len
= strlen(d_there
);
1144 if (d_there
[d_there_len
- 1] != '/') {
1145 d_there
= charealloc(d_there
, d_there_len
+ 2);
1146 strcat(d_there
, "/");
1150 /* Search for the last slash in d_there. */
1151 last_slash
= strrchr(d_there
, '/');
1153 /* If we didn't find one, then make sure the answer is in the format
1154 * "d_here/d_there". */
1155 if (last_slash
== NULL
) {
1158 d_there_file
= d_there
;
1161 /* If path_only is FALSE, then save the filename portion of the
1162 * answer (everything after the last slash) in d_there_file. */
1164 d_there_file
= mallocstrcpy(NULL
, last_slash
+ 1);
1166 /* Remove the filename portion of the answer from d_there. */
1167 null_at(&d_there
, last_slash
- d_there
+ 1);
1169 /* Go to the path specified in d_there. */
1170 if (chdir(d_there
) == -1) {
1176 /* Get the full path. */
1177 d_there
= charalloc(PATH_MAX
+ 1);
1178 d_there
= getcwd(d_there
, PATH_MAX
+ 1);
1180 /* If we succeeded, canonicalize it in d_there. */
1181 if (d_there
!= NULL
) {
1184 /* If the current directory isn't "/", tack a slash onto
1186 if (strcmp(d_there
, "/") != 0) {
1187 d_there
= charealloc(d_there
, strlen(d_there
) + 2);
1188 strcat(d_there
, "/");
1191 /* Otherwise, set path_only to TRUE, so that we clean up
1192 * correctly, free all allocated memory, and return
1196 /* Finally, go back to the path specified in d_here,
1197 * where we were before. We don't check for a chdir()
1198 * error, since we can do nothing if we get one. */
1199 IGNORE_CALL_RESULT(chdir(d_here
));
1201 /* Free d_here, since we're done using it. */
1206 /* At this point, if path_only is FALSE and d_there isn't NULL,
1207 * d_there contains the path portion of the answer and d_there_file
1208 * contains the filename portion of the answer. If this is the
1209 * case, tack the latter onto the end of the former. d_there will
1210 * then contain the complete answer. */
1211 if (!path_only
&& d_there
!= NULL
) {
1212 d_there
= charealloc(d_there
, strlen(d_there
) +
1213 strlen(d_there_file
) + 1);
1214 strcat(d_there
, d_there_file
);
1217 /* Free d_there_file, since we're done using it. */
1218 if (d_there_file
!= NULL
)
1224 /* Return the full version of path, as returned by get_full_path(). On
1225 * error, if path doesn't reference a directory, or if the directory
1226 * isn't writable, return NULL. */
1227 char *check_writable_directory(const char *path
)
1229 char *full_path
= get_full_path(path
);
1231 /* If get_full_path() fails, return NULL. */
1232 if (full_path
== NULL
)
1235 /* If we can't write to path or path isn't a directory, return
1237 if (access(full_path
, W_OK
) != 0 ||
1238 full_path
[strlen(full_path
) - 1] != '/') {
1243 /* Otherwise, return the full path. */
1247 /* This function calls mkstemp(($TMPDIR|P_tmpdir|/tmp/)"nano.XXXXXX").
1248 * On success, it returns the malloc()ed filename and corresponding FILE
1249 * stream, opened in "r+b" mode. On error, it returns NULL for the
1250 * filename and leaves the FILE stream unchanged. */
1251 char *safe_tempfile(FILE **f
)
1253 char *full_tempdir
= NULL
;
1254 const char *tmpdir_env
;
1256 mode_t original_umask
= 0;
1260 /* If $TMPDIR is set, set tempdir to it, run it through
1261 * get_full_path(), and save the result in full_tempdir. Otherwise,
1262 * leave full_tempdir set to NULL. */
1263 tmpdir_env
= getenv("TMPDIR");
1264 if (tmpdir_env
!= NULL
)
1265 full_tempdir
= check_writable_directory(tmpdir_env
);
1267 /* If $TMPDIR is unset, empty, or not a writable directory, and
1268 * full_tempdir is NULL, try P_tmpdir instead. */
1269 if (full_tempdir
== NULL
)
1270 full_tempdir
= check_writable_directory(P_tmpdir
);
1272 /* if P_tmpdir is NULL, use /tmp. */
1273 if (full_tempdir
== NULL
)
1274 full_tempdir
= mallocstrcpy(NULL
, "/tmp/");
1276 full_tempdir
= charealloc(full_tempdir
, strlen(full_tempdir
) + 12);
1277 strcat(full_tempdir
, "nano.XXXXXX");
1279 original_umask
= umask(0);
1280 umask(S_IRWXG
| S_IRWXO
);
1282 fd
= mkstemp(full_tempdir
);
1285 *f
= fdopen(fd
, "r+b");
1288 full_tempdir
= NULL
;
1291 umask(original_umask
);
1293 return full_tempdir
;
1296 #ifndef DISABLE_OPERATINGDIR
1297 /* Initialize full_operating_dir based on operating_dir. */
1298 void init_operating_dir(void)
1300 assert(full_operating_dir
== NULL
);
1302 if (operating_dir
== NULL
)
1305 full_operating_dir
= get_full_path(operating_dir
);
1307 /* If get_full_path() failed or the operating directory is
1308 * inaccessible, unset operating_dir. */
1309 if (full_operating_dir
== NULL
|| chdir(full_operating_dir
) == -1) {
1310 free(full_operating_dir
);
1311 full_operating_dir
= NULL
;
1312 free(operating_dir
);
1313 operating_dir
= NULL
;
1317 /* Check to see if we're inside the operating directory. Return FALSE
1318 * if we are, or TRUE otherwise. If allow_tabcomp is TRUE, allow
1319 * incomplete names that would be matches for the operating directory,
1320 * so that tab completion will work. */
1321 bool check_operating_dir(const char *currpath
, bool allow_tabcomp
)
1323 /* full_operating_dir is global for memory cleanup. It should have
1324 * already been initialized by init_operating_dir(). Also, a
1325 * relative operating directory path will only be handled properly
1326 * if this is done. */
1329 bool retval
= FALSE
;
1330 const char *whereami1
, *whereami2
= NULL
;
1332 /* If no operating directory is set, don't bother doing anything. */
1333 if (operating_dir
== NULL
)
1336 assert(full_operating_dir
!= NULL
);
1338 fullpath
= get_full_path(currpath
);
1340 /* If fullpath is NULL, it means some directory in the path doesn't
1341 * exist or is unreadable. If allow_tabcomp is FALSE, then currpath
1342 * is what the user typed somewhere. We don't want to report a
1343 * non-existent directory as being outside the operating directory,
1344 * so we return FALSE. If allow_tabcomp is TRUE, then currpath
1345 * exists, but is not executable. So we say it isn't in the
1346 * operating directory. */
1347 if (fullpath
== NULL
)
1348 return allow_tabcomp
;
1350 whereami1
= strstr(fullpath
, full_operating_dir
);
1352 whereami2
= strstr(full_operating_dir
, fullpath
);
1354 /* If both searches failed, we're outside the operating directory.
1355 * Otherwise, check the search results. If the full operating
1356 * directory path is not at the beginning of the full current path
1357 * (for normal usage) and vice versa (for tab completion, if we're
1358 * allowing it), we're outside the operating directory. */
1359 if (whereami1
!= fullpath
&& whereami2
!= full_operating_dir
)
1363 /* Otherwise, we're still inside it. */
1369 void init_backup_dir(void)
1371 char *full_backup_dir
;
1373 if (backup_dir
== NULL
)
1376 full_backup_dir
= get_full_path(backup_dir
);
1378 /* If get_full_path() failed or the backup directory is
1379 * inaccessible, unset backup_dir. */
1380 if (full_backup_dir
== NULL
||
1381 full_backup_dir
[strlen(full_backup_dir
) - 1] != '/') {
1382 free(full_backup_dir
);
1387 backup_dir
= full_backup_dir
;
1392 /* Read from inn, write to out. We assume inn is opened for reading,
1393 * and out for writing. We return 0 on success, -1 on read error, or -2
1394 * on write error. */
1395 int copy_file(FILE *inn
, FILE *out
)
1401 assert(inn
!= NULL
&& out
!= NULL
&& inn
!= out
);
1404 charsread
= fread(buf
, sizeof(char), BUFSIZ
, inn
);
1405 if (charsread
== 0 && ferror(inn
)) {
1409 if (fwrite(buf
, sizeof(char), charsread
, out
) < charsread
) {
1413 } while (charsread
> 0);
1415 if (fclose(inn
) == EOF
)
1417 if (fclose(out
) == EOF
)
1423 /* Write a file out to disk. If f_open isn't NULL, we assume that it is
1424 * a stream associated with the file, and we don't try to open it
1425 * ourselves. If tmp is TRUE, we set the umask to disallow anyone else
1426 * from accessing the file, we don't set the filename to its name, and
1427 * we don't print out how many lines we wrote on the statusbar.
1429 * tmp means we are writing a temporary file in a secure fashion. We
1430 * use it when spell checking or dumping the file on an error. If
1431 * append is APPEND, it means we are appending instead of overwriting.
1432 * If append is PREPEND, it means we are prepending instead of
1433 * overwriting. If nonamechange is TRUE, we don't change the current
1434 * filename. nonamechange is ignored if tmp is FALSE, we're appending,
1435 * or we're prepending.
1437 * Return TRUE on success or FALSE on error. */
1438 bool write_file(const char *name
, FILE *f_open
, bool tmp
, append_type
1439 append
, bool nonamechange
)
1441 bool retval
= FALSE
;
1442 /* Instead of returning in this function, you should always
1443 * set retval and then goto cleanup_and_exit. */
1444 size_t lineswritten
= 0;
1445 const filestruct
*fileptr
= openfile
->fileage
;
1447 /* The file descriptor we use. */
1448 mode_t original_umask
= 0;
1449 /* Our umask, from when nano started. */
1451 /* The result of stat(). TRUE if the file exists, FALSE
1452 * otherwise. If name is a link that points nowhere, realexists
1455 /* The status fields filled in by stat(). */
1457 /* The result of lstat(). The same as realexists, unless name
1460 /* The status fields filled in by lstat(). */
1462 /* name after tilde expansion. */
1464 /* The actual file, realname, we are writing to. */
1465 char *tempname
= NULL
;
1466 /* The temp file name we write to on prepend. */
1469 assert(name
!= NULL
);
1480 realname
= real_dir_from_tilde(name
);
1482 #ifndef DISABLE_OPERATINGDIR
1483 /* If we're writing a temporary file, we're probably going outside
1484 * the operating directory, so skip the operating directory test. */
1485 if (!tmp
&& check_operating_dir(realname
, FALSE
)) {
1486 statusbar(_("Can't write outside of %s"), operating_dir
);
1487 goto cleanup_and_exit
;
1491 anyexists
= (lstat(realname
, &lst
) != -1);
1493 /* If the temp file exists and isn't already open, give up. */
1494 if (tmp
&& anyexists
&& f_open
== NULL
)
1495 goto cleanup_and_exit
;
1497 /* If NOFOLLOW_SYMLINKS is set, it doesn't make sense to prepend or
1498 * append to a symlink. Here we warn about the contradiction. */
1499 if (ISSET(NOFOLLOW_SYMLINKS
) && anyexists
&& S_ISLNK(lst
.st_mode
)) {
1501 _("Cannot prepend or append to a symlink with --nofollow set"));
1502 goto cleanup_and_exit
;
1505 /* Save the state of the file at the end of the symlink (if there is
1507 realexists
= (stat(realname
, &st
) != -1);
1510 /* if we have not stat()d this file before (say, the user just
1511 * specified it interactively), stat and save the value
1512 * or else we will chase null pointers when we do
1513 * modtime checks, preserve file times, etc. during backup */
1514 if (openfile
->current_stat
== NULL
&& !tmp
&& realexists
)
1515 stat(realname
, openfile
->current_stat
);
1517 /* We backup only if the backup toggle is set, the file isn't
1518 * temporary, and the file already exists. Furthermore, if we
1519 * aren't appending, prepending, or writing a selection, we backup
1520 * only if the file has not been modified by someone else since nano
1522 if (ISSET(BACKUP_FILE
) && !tmp
&& realexists
&& ((append
!=
1523 OVERWRITE
|| openfile
->mark_set
) || (openfile
->current_stat
&&
1524 openfile
->current_stat
->st_mtime
== st
.st_mtime
))) {
1528 struct utimbuf filetime
;
1531 /* Save the original file's access and modification times. */
1532 filetime
.actime
= openfile
->current_stat
->st_atime
;
1533 filetime
.modtime
= openfile
->current_stat
->st_mtime
;
1535 if (f_open
== NULL
) {
1536 /* Open the original file to copy to the backup. */
1537 f
= fopen(realname
, "rb");
1540 statusbar(_("Error reading %s: %s"), realname
,
1543 /* If we can't read from the original file, go on, since
1544 * only saving the original file is better than saving
1550 /* If backup_dir is set, we set backupname to
1551 * backup_dir/backupname~[.number], where backupname is the
1552 * canonicalized absolute pathname of realname with every '/'
1553 * replaced with a '!'. This means that /home/foo/file is
1554 * backed up in backup_dir/!home!foo!file~[.number]. */
1555 if (backup_dir
!= NULL
) {
1556 char *backuptemp
= get_full_path(realname
);
1558 if (backuptemp
== NULL
)
1559 /* If get_full_path() failed, we don't have a
1560 * canonicalized absolute pathname, so just use the
1561 * filename portion of the pathname. We use tail() so
1562 * that e.g. ../backupname will be backed up in
1563 * backupdir/backupname~ instead of
1564 * backupdir/../backupname~. */
1565 backuptemp
= mallocstrcpy(NULL
, tail(realname
));
1569 for (; backuptemp
[i
] != '\0'; i
++) {
1570 if (backuptemp
[i
] == '/')
1571 backuptemp
[i
] = '!';
1575 backupname
= charalloc(strlen(backup_dir
) +
1576 strlen(backuptemp
) + 1);
1577 sprintf(backupname
, "%s%s", backup_dir
, backuptemp
);
1579 backuptemp
= get_next_filename(backupname
, "~");
1580 if (*backuptemp
== '\0') {
1581 statusbar(_("Error writing backup file %s: %s"), backupname
,
1582 _("Too many backup files?"));
1585 /* If we can't write to the backup, DONT go on, since
1586 whatever caused the backup file to fail (e.g. disk
1587 full may well cause the real file write to fail, which
1588 means we could lose both the backup and the original! */
1589 goto cleanup_and_exit
;
1592 backupname
= backuptemp
;
1595 backupname
= charalloc(strlen(realname
) + 2);
1596 sprintf(backupname
, "%s~", realname
);
1599 /* First, unlink any existing backups. Next, open the backup
1600 file with O_CREAT and O_EXCL. If it succeeds, we
1601 have a file descriptor to a new backup file. */
1602 if (unlink(backupname
) < 0 && errno
!= ENOENT
&& !ISSET(INSECURE_BACKUP
)) {
1603 statusbar(_("Error writing backup file %s: %s"), backupname
,
1606 goto cleanup_and_exit
;
1609 if (ISSET(INSECURE_BACKUP
))
1610 backup_cflags
= O_WRONLY
| O_CREAT
| O_APPEND
;
1612 backup_cflags
= O_WRONLY
| O_CREAT
| O_EXCL
| O_APPEND
;
1614 backup_fd
= open(backupname
, backup_cflags
,
1615 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
| S_IROTH
| S_IWOTH
);
1616 /* Now we've got a safe file stream. If the previous open()
1617 call failed, this will return NULL. */
1618 backup_file
= fdopen(backup_fd
, "wb");
1620 if (backup_fd
< 0 || backup_file
== NULL
) {
1621 statusbar(_("Error writing backup file %s: %s"), backupname
,
1624 goto cleanup_and_exit
;
1627 /* We shouldn't worry about chown()ing something if we're not
1628 root, since it's likely to fail! */
1629 if (geteuid() == NANO_ROOT_UID
&& fchown(backup_fd
,
1630 openfile
->current_stat
->st_uid
, openfile
->current_stat
->st_gid
) == -1
1631 && !ISSET(INSECURE_BACKUP
)) {
1632 statusbar(_("Error writing backup file %s: %s"), backupname
,
1635 fclose(backup_file
);
1636 goto cleanup_and_exit
;
1639 if (fchmod(backup_fd
, openfile
->current_stat
->st_mode
) == -1 && !ISSET(INSECURE_BACKUP
)) {
1640 statusbar(_("Error writing backup file %s: %s"), backupname
,
1643 fclose(backup_file
);
1644 /* If we can't write to the backup, DONT go on, since
1645 whatever caused the backup file to fail (e.g. disk
1646 full may well cause the real file write to fail, which
1647 means we could lose both the backup and the original! */
1648 goto cleanup_and_exit
;
1652 fprintf(stderr
, "Backing up %s to %s\n", realname
, backupname
);
1655 /* Copy the file. */
1656 copy_status
= copy_file(f
, backup_file
);
1658 if (copy_status
!= 0) {
1659 statusbar(_("Error reading %s: %s"), realname
,
1662 goto cleanup_and_exit
;
1665 /* And set its metadata. */
1666 if (utime(backupname
, &filetime
) == -1 && !ISSET(INSECURE_BACKUP
)) {
1667 statusbar(_("Error writing backup file %s: %s"), backupname
,
1669 /* If we can't write to the backup, DONT go on, since
1670 whatever caused the backup file to fail (e.g. disk
1671 full may well cause the real file write to fail, which
1672 means we could lose both the backup and the original! */
1673 goto cleanup_and_exit
;
1680 #endif /* !NANO_TINY */
1682 /* If NOFOLLOW_SYMLINKS is set and the file is a link, we aren't
1683 * doing prepend or append. So we delete the link first, and just
1685 if (ISSET(NOFOLLOW_SYMLINKS
) && anyexists
&& S_ISLNK(lst
.st_mode
) &&
1686 unlink(realname
) == -1) {
1687 statusbar(_("Error writing %s: %s"), realname
, strerror(errno
));
1688 goto cleanup_and_exit
;
1691 if (f_open
== NULL
) {
1692 original_umask
= umask(0);
1694 /* If we create a temp file, we don't let anyone else access it.
1695 * We create a temp file if tmp is TRUE. */
1697 umask(S_IRWXG
| S_IRWXO
);
1699 umask(original_umask
);
1702 /* If we're prepending, copy the file to a temp file. */
1703 if (append
== PREPEND
) {
1705 FILE *f_source
= NULL
;
1708 f
= fopen(realname
, "rb");
1711 statusbar(_("Error reading %s: %s"), realname
,
1714 goto cleanup_and_exit
;
1718 tempname
= safe_tempfile(&f
);
1720 if (tempname
== NULL
) {
1721 statusbar(_("Error writing temp file: %s"),
1723 goto cleanup_and_exit
;
1726 if (f_open
== NULL
) {
1727 fd_source
= open(realname
, O_RDONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
);
1729 if (fd_source
!= -1) {
1730 f_source
= fdopen(fd_source
, "rb");
1731 if (f_source
== NULL
) {
1732 statusbar(_("Error reading %s: %s"), realname
,
1738 goto cleanup_and_exit
;
1743 if (copy_file(f_source
, f
) != 0) {
1744 statusbar(_("Error writing %s: %s"), tempname
,
1747 goto cleanup_and_exit
;
1751 if (f_open
== NULL
) {
1752 /* Now open the file in place. Use O_EXCL if tmp is TRUE. This
1753 * is copied from joe, because wiggy says so *shrug*. */
1754 fd
= open(realname
, O_WRONLY
| O_CREAT
| ((append
== APPEND
) ?
1755 O_APPEND
: (tmp
? O_EXCL
: O_TRUNC
)), S_IRUSR
|
1756 S_IWUSR
| S_IRGRP
| S_IWGRP
| S_IROTH
| S_IWOTH
);
1758 /* Set the umask back to the user's original value. */
1759 umask(original_umask
);
1761 /* If we couldn't open the file, give up. */
1763 statusbar(_("Error writing %s: %s"), realname
,
1766 /* tempname has been set only if we're prepending. */
1767 if (tempname
!= NULL
)
1769 goto cleanup_and_exit
;
1772 f
= fdopen(fd
, (append
== APPEND
) ? "ab" : "wb");
1775 statusbar(_("Error writing %s: %s"), realname
,
1778 goto cleanup_and_exit
;
1782 /* There might not be a magicline. There won't be when writing out
1784 assert(openfile
->fileage
!= NULL
&& openfile
->filebot
!= NULL
);
1786 while (fileptr
!= NULL
) {
1787 size_t data_len
= strlen(fileptr
->data
), size
;
1789 /* Convert newlines to nulls, just before we write to disk. */
1790 sunder(fileptr
->data
);
1792 size
= fwrite(fileptr
->data
, sizeof(char), data_len
, f
);
1794 /* Convert nulls to newlines. data_len is the string's real
1796 unsunder(fileptr
->data
, data_len
);
1798 if (size
< data_len
) {
1799 statusbar(_("Error writing %s: %s"), realname
,
1802 goto cleanup_and_exit
;
1805 /* If we're on the last line of the file, don't write a newline
1806 * character after it. If the last line of the file is blank,
1807 * this means that zero bytes are written, in which case we
1808 * don't count the last line in the total lines written. */
1809 if (fileptr
== openfile
->filebot
) {
1810 if (fileptr
->data
[0] == '\0')
1814 if (openfile
->fmt
== DOS_FILE
|| openfile
->fmt
==
1816 if (putc('\r', f
) == EOF
) {
1817 statusbar(_("Error writing %s: %s"), realname
,
1820 goto cleanup_and_exit
;
1824 if (openfile
->fmt
!= MAC_FILE
) {
1826 if (putc('\n', f
) == EOF
) {
1827 statusbar(_("Error writing %s: %s"), realname
,
1830 goto cleanup_and_exit
;
1837 fileptr
= fileptr
->next
;
1841 /* If we're prepending, open the temp file, and append it to f. */
1842 if (append
== PREPEND
) {
1844 FILE *f_source
= NULL
;
1846 fd_source
= open(tempname
, O_RDONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
);
1848 if (fd_source
!= -1) {
1849 f_source
= fdopen(fd_source
, "rb");
1850 if (f_source
== NULL
)
1854 if (f_source
== NULL
) {
1855 statusbar(_("Error reading %s: %s"), tempname
,
1859 goto cleanup_and_exit
;
1862 if (copy_file(f_source
, f
) == -1 || unlink(tempname
) == -1) {
1863 statusbar(_("Error writing %s: %s"), realname
,
1865 goto cleanup_and_exit
;
1867 } else if (fclose(f
) != 0) {
1868 statusbar(_("Error writing %s: %s"), realname
,
1870 goto cleanup_and_exit
;
1873 if (!tmp
&& append
== OVERWRITE
) {
1874 if (!nonamechange
) {
1875 openfile
->filename
= mallocstrcpy(openfile
->filename
,
1878 /* We might have changed the filename, so update the colors
1879 * to account for it, and then make sure we're using
1884 /* If color syntaxes are available and turned on, we need to
1885 * call edit_refresh(). */
1886 if (openfile
->colorstrings
!= NULL
&&
1887 !ISSET(NO_COLOR_SYNTAX
))
1893 /* Update current_stat to reference the file as it is now. */
1894 if (openfile
->current_stat
== NULL
)
1895 openfile
->current_stat
=
1896 (struct stat
*)nmalloc(sizeof(struct stat
));
1897 stat(realname
, openfile
->current_stat
);
1900 statusbar(P_("Wrote %lu line", "Wrote %lu lines",
1901 (unsigned long)lineswritten
),
1902 (unsigned long)lineswritten
);
1903 openfile
->modified
= FALSE
;
1911 if (tempname
!= NULL
)
1918 /* Write a marked selection from a file out to disk. Return TRUE on
1919 * success or FALSE on error. */
1920 bool write_marked_file(const char *name
, FILE *f_open
, bool tmp
,
1924 bool old_modified
= openfile
->modified
;
1925 /* write_file() unsets the modified flag. */
1926 bool added_magicline
= FALSE
;
1927 /* Whether we added a magicline after filebot. */
1928 filestruct
*top
, *bot
;
1929 size_t top_x
, bot_x
;
1931 assert(openfile
->mark_set
);
1933 /* Partition the filestruct so that it contains only the marked
1935 mark_order((const filestruct
**)&top
, &top_x
,
1936 (const filestruct
**)&bot
, &bot_x
, NULL
);
1937 filepart
= partition_filestruct(top
, top_x
, bot
, bot_x
);
1939 /* Handle the magicline if the NO_NEWLINES flag isn't set. If the
1940 * line at filebot is blank, treat it as the magicline and hence the
1941 * end of the file. Otherwise, add a magicline and treat it as the
1942 * end of the file. */
1943 if (!ISSET(NO_NEWLINES
) &&
1944 (added_magicline
= (openfile
->filebot
->data
[0] != '\0')))
1947 retval
= write_file(name
, f_open
, tmp
, append
, TRUE
);
1949 /* If the NO_NEWLINES flag isn't set, and we added a magicline,
1951 if (!ISSET(NO_NEWLINES
) && added_magicline
)
1954 /* Unpartition the filestruct so that it contains all the text
1956 unpartition_filestruct(&filepart
);
1963 #endif /* !NANO_TINY */
1965 /* Write the current file to disk. If the mark is on, write the current
1966 * marked selection to disk. If exiting is TRUE, write the file to disk
1967 * regardless of whether the mark is on, and without prompting if the
1968 * TEMP_FILE flag is set. Return TRUE on success or FALSE on error. */
1969 bool do_writeout(bool exiting
)
1972 append_type append
= OVERWRITE
;
1974 /* The last answer the user typed at the statusbar prompt. */
1976 static bool did_credits
= FALSE
;
1978 bool retval
= FALSE
, meta_key
= FALSE
, func_key
= FALSE
;
1981 currmenu
= MWRITEFILE
;
1983 if (exiting
&& openfile
->filename
[0] != '\0' && ISSET(TEMP_FILE
)) {
1984 retval
= write_file(openfile
->filename
, NULL
, FALSE
, OVERWRITE
,
1987 /* Write succeeded. */
1992 ans
= mallocstrcpy(NULL
,
1994 (!exiting
&& openfile
->mark_set
) ? "" :
1996 openfile
->filename
);
2001 const char *formatstr
, *backupstr
;
2003 formatstr
= (openfile
->fmt
== DOS_FILE
) ?
2004 _(" [DOS Format]") : (openfile
->fmt
== MAC_FILE
) ?
2005 _(" [Mac Format]") : "";
2007 backupstr
= ISSET(BACKUP_FILE
) ? _(" [Backup]") : "";
2009 /* If we're using restricted mode, don't display the "Write
2010 * Selection to File" prompt. This function is disabled, since
2011 * it allows reading from or writing to files not specified on
2012 * the command line. */
2013 if (!ISSET(RESTRICTED
) && !exiting
&& openfile
->mark_set
)
2014 msg
= (append
== PREPEND
) ?
2015 _("Prepend Selection to File") : (append
== APPEND
) ?
2016 _("Append Selection to File") :
2017 _("Write Selection to File");
2019 #endif /* !NANO_TINY */
2020 msg
= (append
== PREPEND
) ? _("File Name to Prepend to") :
2021 (append
== APPEND
) ? _("File Name to Append to") :
2022 _("File Name to Write");
2024 /* If we're using restricted mode, the filename isn't blank,
2025 * and we're at the "Write File" prompt, disable tab
2027 i
= do_prompt(!ISSET(RESTRICTED
) ||
2028 openfile
->filename
[0] == '\0',
2029 #ifndef DISABLE_TABCOMP
2033 &meta_key
, &func_key
,
2037 edit_refresh
, "%s%s%s", msg
,
2039 formatstr
, backupstr
2045 /* If the filename or command begins with a newline (i.e. an
2046 * encoded null), treat it as though it's blank. */
2047 if (i
< 0 || *answer
== '\n') {
2048 statusbar(_("Cancelled"));
2052 ans
= mallocstrcpy(ans
, answer
);
2053 s
= get_shortcut(currmenu
, &i
, &meta_key
, &func_key
);
2055 #ifndef DISABLE_BROWSER
2056 if (s
&& s
->scfunc
== TO_FILES_MSG
) {
2057 char *tmp
= do_browse_from(answer
);
2062 /* We have a file now. Indicate this. */
2066 #endif /* !DISABLE_BROWSER */
2068 if (s
&& s
->scfunc
== DOS_FORMAT_MSG
) {
2069 openfile
->fmt
= (openfile
->fmt
== DOS_FILE
) ? NIX_FILE
:
2072 } else if (s
&& s
->scfunc
== MAC_FORMAT_MSG
) {
2073 openfile
->fmt
= (openfile
->fmt
== MAC_FILE
) ? NIX_FILE
:
2076 } else if (s
&& s
->scfunc
== BACKUP_FILE_MSG
) {
2077 TOGGLE(BACKUP_FILE
);
2080 #endif /* !NANO_TINY */
2081 if (s
&& s
->scfunc
== PREPEND_MSG
) {
2082 append
= (append
== PREPEND
) ? OVERWRITE
: PREPEND
;
2084 } else if (s
&& s
->scfunc
== APPEND_MSG
) {
2085 append
= (append
== APPEND
) ? OVERWRITE
: APPEND
;
2087 } else if (s
&& s
->scfunc
== DO_HELP_VOID
) {
2092 fprintf(stderr
, "filename is %s\n", answer
);
2096 /* If the current file has been modified, we've pressed
2097 * Ctrl-X at the edit window to exit, we've pressed "y" at
2098 * the "Save modified buffer" prompt to save, we've entered
2099 * "zzy" as the filename to save under (hence "xyzzy"), and
2100 * this is the first time we've done this, show an Easter
2101 * egg. Display the credits. */
2102 if (!did_credits
&& exiting
&& !ISSET(TEMP_FILE
) &&
2103 strcasecmp(answer
, "zzy") == 0) {
2111 if (append
== OVERWRITE
) {
2112 size_t answer_len
= strlen(answer
);
2113 bool name_exists
, do_warning
;
2114 char *full_answer
, *full_filename
;
2117 /* Convert newlines to nulls, just before we get the
2121 full_answer
= get_full_path(answer
);
2122 full_filename
= get_full_path(openfile
->filename
);
2123 name_exists
= (stat((full_answer
== NULL
) ? answer
:
2124 full_answer
, &st
) != -1);
2125 if (openfile
->filename
[0] == '\0')
2126 do_warning
= name_exists
;
2128 do_warning
= (strcmp((full_answer
== NULL
) ?
2129 answer
: full_answer
, (full_filename
== NULL
) ?
2130 openfile
->filename
: full_filename
) != 0);
2132 /* Convert nulls to newlines. answer_len is the
2133 * string's real length. */
2134 unsunder(answer
, answer_len
);
2136 if (full_filename
!= NULL
)
2137 free(full_filename
);
2138 if (full_answer
!= NULL
)
2142 /* If we're using restricted mode, we aren't allowed
2143 * to overwrite an existing file with the current
2144 * file. We also aren't allowed to change the name
2145 * of the current file if it has one, because that
2146 * would allow reading from or writing to files not
2147 * specified on the command line. */
2148 if (ISSET(RESTRICTED
))
2152 i
= do_yesno_prompt(FALSE
,
2153 _("File exists, OVERWRITE ? "));
2154 if (i
== 0 || i
== -1)
2158 if (exiting
|| !openfile
->mark_set
)
2161 i
= do_yesno_prompt(FALSE
,
2162 _("Save file under DIFFERENT NAME ? "));
2163 if (i
== 0 || i
== -1)
2168 /* Complain if the file exists, the name hasn't changed, and the
2169 stat information we had before does not match what we have now */
2170 else if (name_exists
&& openfile
->current_stat
&& (openfile
->current_stat
->st_mtime
< st
.st_mtime
||
2171 openfile
->current_stat
->st_dev
!= st
.st_dev
|| openfile
->current_stat
->st_ino
!= st
.st_ino
)) {
2172 i
= do_yesno_prompt(FALSE
,
2173 _("File was modified since you opened it, continue saving ? "));
2174 if (i
== 0 || i
== -1)
2181 /* Convert newlines to nulls, just before we save the
2186 /* Here's where we allow the selected text to be written to
2187 * a separate file. If we're using restricted mode, this
2188 * function is disabled, since it allows reading from or
2189 * writing to files not specified on the command line. */
2192 (!ISSET(RESTRICTED
) && !exiting
&& openfile
->mark_set
) ?
2193 write_marked_file(answer
, NULL
, FALSE
, append
) :
2195 write_file(answer
, NULL
, FALSE
, append
, FALSE
);
2206 /* Write the current file to disk. If the mark is on, write the current
2207 * marked selection to disk. */
2208 void do_writeout_void(void)
2211 display_main_list();
2214 /* Return a malloc()ed string containing the actual directory, used to
2215 * convert ~user/ and ~/ notation. */
2216 char *real_dir_from_tilde(const char *buf
)
2220 assert(buf
!= NULL
);
2226 /* Figure out how much of the string we need to compare. */
2227 for (; buf
[i
] != '/' && buf
[i
] != '\0'; i
++)
2230 /* Get the home directory. */
2233 tilde_dir
= mallocstrcpy(NULL
, homedir
);
2235 const struct passwd
*userdata
;
2237 tilde_dir
= mallocstrncpy(NULL
, buf
, i
+ 1);
2238 tilde_dir
[i
] = '\0';
2241 userdata
= getpwent();
2242 } while (userdata
!= NULL
&& strcmp(userdata
->pw_name
,
2243 tilde_dir
+ 1) != 0);
2245 if (userdata
!= NULL
)
2246 tilde_dir
= mallocstrcpy(tilde_dir
, userdata
->pw_dir
);
2249 retval
= charalloc(strlen(tilde_dir
) + strlen(buf
+ i
) + 1);
2250 sprintf(retval
, "%s%s", tilde_dir
, buf
+ i
);
2254 retval
= mallocstrcpy(NULL
, buf
);
2259 #if !defined(DISABLE_TABCOMP) || !defined(DISABLE_BROWSER)
2260 /* Our sort routine for file listings. Sort alphabetically and
2261 * case-insensitively, and sort directories before filenames. */
2262 int diralphasort(const void *va
, const void *vb
)
2264 struct stat fileinfo
;
2265 const char *a
= *(const char *const *)va
;
2266 const char *b
= *(const char *const *)vb
;
2267 bool aisdir
= stat(a
, &fileinfo
) != -1 && S_ISDIR(fileinfo
.st_mode
);
2268 bool bisdir
= stat(b
, &fileinfo
) != -1 && S_ISDIR(fileinfo
.st_mode
);
2270 if (aisdir
&& !bisdir
)
2272 if (!aisdir
&& bisdir
)
2275 /* Standard function brain damage: We should be sorting
2276 * alphabetically and case-insensitively according to the current
2277 * locale, but there's no standard strcasecoll() function, so we
2278 * have to use multibyte strcasecmp() instead, */
2279 return mbstrcasecmp(a
, b
);
2282 /* Free the memory allocated for array, which should contain len
2284 void free_chararray(char **array
, size_t len
)
2286 assert(array
!= NULL
);
2288 for (; len
> 0; len
--)
2289 free(array
[len
- 1]);
2294 #ifndef DISABLE_TABCOMP
2295 /* Is the given path a directory? */
2296 bool is_dir(const char *buf
)
2299 struct stat fileinfo
;
2302 assert(buf
!= NULL
);
2304 dirptr
= real_dir_from_tilde(buf
);
2306 retval
= (stat(dirptr
, &fileinfo
) != -1 &&
2307 S_ISDIR(fileinfo
.st_mode
));
2314 /* These functions, username_tab_completion(), cwd_tab_completion()
2315 * (originally exe_n_cwd_tab_completion()), and input_tab(), were
2316 * adapted from busybox 0.46 (cmdedit.c). Here is the notice from that
2317 * file, with the copyright years updated:
2319 * Termios command line History and Editting, originally
2320 * intended for NetBSD sh (ash)
2321 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
2322 * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
2323 * Etc: Dave Cinege <dcinege@psychosis.com>
2324 * Majorly adjusted/re-written for busybox:
2325 * Erik Andersen <andersee@debian.org>
2327 * You may use this code as you wish, so long as the original author(s)
2328 * are attributed in any redistributions of the source code.
2329 * This code is 'as is' with no warranty.
2330 * This code may safely be consumed by a BSD or GPL license. */
2332 /* We consider the first buf_len characters of buf for ~username tab
2334 char **username_tab_completion(const char *buf
, size_t *num_matches
,
2337 char **matches
= NULL
;
2338 const struct passwd
*userdata
;
2340 assert(buf
!= NULL
&& num_matches
!= NULL
&& buf_len
> 0);
2344 while ((userdata
= getpwent()) != NULL
) {
2345 if (strncmp(userdata
->pw_name
, buf
+ 1, buf_len
- 1) == 0) {
2346 /* Cool, found a match. Add it to the list. This makes a
2347 * lot more sense to me (Chris) this way... */
2349 #ifndef DISABLE_OPERATINGDIR
2350 /* ...unless the match exists outside the operating
2351 * directory, in which case just go to the next match. */
2352 if (check_operating_dir(userdata
->pw_dir
, TRUE
))
2356 matches
= (char **)nrealloc(matches
, (*num_matches
+ 1) *
2358 matches
[*num_matches
] =
2359 charalloc(strlen(userdata
->pw_name
) + 2);
2360 sprintf(matches
[*num_matches
], "~%s", userdata
->pw_name
);
2369 /* We consider the first buf_len characters of buf for filename tab
2371 char **cwd_tab_completion(const char *buf
, bool allow_files
, size_t
2372 *num_matches
, size_t buf_len
)
2374 char *dirname
= mallocstrcpy(NULL
, buf
), *filename
;
2375 #ifndef DISABLE_OPERATINGDIR
2379 char **matches
= NULL
;
2381 const struct dirent
*nextdir
;
2383 assert(dirname
!= NULL
&& num_matches
!= NULL
);
2386 null_at(&dirname
, buf_len
);
2388 /* Okie, if there's a / in the buffer, strip out the directory
2390 filename
= strrchr(dirname
, '/');
2391 if (filename
!= NULL
) {
2392 char *tmpdirname
= filename
+ 1;
2394 filename
= mallocstrcpy(NULL
, tmpdirname
);
2396 tmpdirname
= dirname
;
2397 dirname
= real_dir_from_tilde(dirname
);
2401 dirname
= mallocstrcpy(NULL
, "./");
2404 assert(dirname
[strlen(dirname
) - 1] == '/');
2406 dir
= opendir(dirname
);
2409 /* Don't print an error, just shut up and return. */
2416 #ifndef DISABLE_OPERATINGDIR
2417 dirnamelen
= strlen(dirname
);
2419 filenamelen
= strlen(filename
);
2421 while ((nextdir
= readdir(dir
)) != NULL
) {
2422 bool skip_match
= FALSE
;
2425 fprintf(stderr
, "Comparing \'%s\'\n", nextdir
->d_name
);
2427 /* See if this matches. */
2428 if (strncmp(nextdir
->d_name
, filename
, filenamelen
) == 0 &&
2429 (*filename
== '.' || (strcmp(nextdir
->d_name
, ".") !=
2430 0 && strcmp(nextdir
->d_name
, "..") != 0))) {
2431 /* Cool, found a match. Add it to the list. This makes a
2432 * lot more sense to me (Chris) this way... */
2434 char *tmp
= charalloc(strlen(dirname
) +
2435 strlen(nextdir
->d_name
) + 1);
2436 sprintf(tmp
, "%s%s", dirname
, nextdir
->d_name
);
2438 #ifndef DISABLE_OPERATINGDIR
2439 /* ...unless the match exists outside the operating
2440 * directory, in which case just go to the next match. */
2441 if (check_operating_dir(tmp
, TRUE
))
2445 /* ...or unless the match isn't a directory and allow_files
2446 * isn't set, in which case just go to the next match. */
2447 if (!allow_files
&& !is_dir(tmp
))
2455 matches
= (char **)nrealloc(matches
, (*num_matches
+ 1) *
2457 matches
[*num_matches
] = mallocstrcpy(NULL
, nextdir
->d_name
);
2469 /* Do tab completion. place refers to how much the statusbar cursor
2470 * position should be advanced. refresh_func is the function we will
2471 * call to refresh the edit window. */
2472 char *input_tab(char *buf
, bool allow_files
, size_t *place
, bool
2473 *lastwastab
, void (*refresh_func
)(void), bool *list
)
2475 size_t num_matches
= 0, buf_len
;
2476 char **matches
= NULL
;
2478 assert(buf
!= NULL
&& place
!= NULL
&& *place
<= strlen(buf
) && lastwastab
!= NULL
&& refresh_func
!= NULL
&& list
!= NULL
);
2482 /* If the word starts with `~' and there is no slash in the word,
2483 * then try completing this word as a username. */
2484 if (*place
> 0 && *buf
== '~') {
2485 const char *bob
= strchr(buf
, '/');
2487 if (bob
== NULL
|| bob
>= buf
+ *place
)
2488 matches
= username_tab_completion(buf
, &num_matches
,
2492 /* Match against files relative to the current working directory. */
2493 if (matches
== NULL
)
2494 matches
= cwd_tab_completion(buf
, allow_files
, &num_matches
,
2497 buf_len
= strlen(buf
);
2499 if (num_matches
== 0 || *place
!= buf_len
)
2502 size_t match
, common_len
= 0;
2504 const char *lastslash
= revstrstr(buf
, "/", buf
+ *place
);
2505 size_t lastslash_len
= (lastslash
== NULL
) ? 0 :
2506 lastslash
- buf
+ 1;
2507 char *match1_mb
= charalloc(mb_cur_max() + 1);
2508 char *match2_mb
= charalloc(mb_cur_max() + 1);
2509 int match1_mb_len
, match2_mb_len
;
2512 for (match
= 1; match
< num_matches
; match
++) {
2513 /* Get the number of single-byte characters that all the
2514 * matches have in common. */
2515 match1_mb_len
= parse_mbchar(matches
[0] + common_len
,
2517 match2_mb_len
= parse_mbchar(matches
[match
] +
2518 common_len
, match2_mb
, NULL
);
2519 match1_mb
[match1_mb_len
] = '\0';
2520 match2_mb
[match2_mb_len
] = '\0';
2521 if (strcmp(match1_mb
, match2_mb
) != 0)
2525 if (match
< num_matches
|| matches
[0][common_len
] == '\0')
2528 common_len
+= parse_mbchar(buf
+ common_len
, NULL
, NULL
);
2534 mzero
= charalloc(lastslash_len
+ common_len
+ 1);
2536 strncpy(mzero
, buf
, lastslash_len
);
2537 strncpy(mzero
+ lastslash_len
, matches
[0], common_len
);
2539 common_len
+= lastslash_len
;
2540 mzero
[common_len
] = '\0';
2542 assert(common_len
>= *place
);
2544 if (num_matches
== 1 && is_dir(mzero
)) {
2545 mzero
[common_len
++] = '/';
2547 assert(common_len
> *place
);
2550 if (num_matches
> 1 && (common_len
!= *place
|| !*lastwastab
))
2553 /* If there is more of a match to display on the statusbar, show
2554 * it. We reset lastwastab to FALSE: it requires pressing Tab
2555 * twice in succession with no statusbar changes to see a match
2557 if (common_len
!= *place
) {
2558 *lastwastab
= FALSE
;
2559 buf
= charealloc(buf
, common_len
+ buf_len
- *place
+ 1);
2560 charmove(buf
+ common_len
, buf
+ *place
, buf_len
-
2562 strncpy(buf
, mzero
, common_len
);
2563 *place
= common_len
;
2564 } else if (!*lastwastab
|| num_matches
< 2)
2567 int longest_name
= 0, ncols
, editline
= 0;
2569 /* Now we show a list of the available choices. */
2570 assert(num_matches
> 1);
2572 /* Sort the list. */
2573 qsort(matches
, num_matches
, sizeof(char *), diralphasort
);
2575 for (match
= 0; match
< num_matches
; match
++) {
2576 common_len
= strnlenpt(matches
[match
], COLS
- 1);
2578 if (common_len
> COLS
- 1) {
2579 longest_name
= COLS
- 1;
2583 if (common_len
> longest_name
)
2584 longest_name
= common_len
;
2587 assert(longest_name
<= COLS
- 1);
2589 /* Each column will be (longest_name + 2) columns wide, i.e.
2590 * two spaces between columns, except that there will be
2591 * only one space after the last column. */
2592 ncols
= (COLS
+ 1) / (longest_name
+ 2);
2594 /* Blank the edit window, and print the matches out
2599 /* Disable el cursor. */
2602 for (match
= 0; match
< num_matches
; match
++) {
2605 wmove(edit
, editline
, (longest_name
+ 2) *
2608 if (match
% ncols
== 0 &&
2609 editline
== editwinrows
- 1 &&
2610 num_matches
- match
> ncols
) {
2611 waddstr(edit
, _("(more)"));
2615 disp
= display_string(matches
[match
], 0, longest_name
,
2617 waddstr(edit
, disp
);
2620 if ((match
+ 1) % ncols
== 0)
2631 free_chararray(matches
, num_matches
);
2633 /* Only refresh the edit window if we don't have a list of filename
2638 /* Enable el cursor. */
2643 #endif /* !DISABLE_TABCOMP */
2645 /* Only print the last part of a path. Isn't there a shell command for
2647 const char *tail(const char *foo
)
2649 const char *tmp
= strrchr(foo
, '/');
2659 #if !defined(NANO_TINY) && defined(ENABLE_NANORC)
2660 /* Return $HOME/.nano_history, or NULL if we can't find the home
2661 * directory. The string is dynamically allocated, and should be
2663 char *histfilename(void)
2665 char *nanohist
= NULL
;
2667 if (homedir
!= NULL
) {
2668 size_t homelen
= strlen(homedir
);
2670 nanohist
= charalloc(homelen
+ 15);
2671 strcpy(nanohist
, homedir
);
2672 strcpy(nanohist
+ homelen
, "/.nano_history");
2678 /* Load histories from ~/.nano_history. */
2679 void load_history(void)
2681 char *nanohist
= histfilename();
2683 /* Assume do_rcfile() has reported a missing home directory. */
2684 if (nanohist
!= NULL
) {
2685 FILE *hist
= fopen(nanohist
, "rb");
2688 if (errno
!= ENOENT
) {
2689 /* Don't save history when we quit. */
2691 rcfile_error(N_("Error reading %s: %s"), nanohist
,
2694 _("\nPress Enter to continue starting nano.\n"));
2695 while (getchar() != '\n')
2699 /* Load a history list (first the search history, then the
2700 * replace history) from the oldest entry to the newest.
2701 * Assume the last history entry is a blank line. */
2702 filestruct
**history
= &search_history
;
2707 while ((read
= getline(&line
, &buf_len
, hist
)) >= 0) {
2708 if (read
> 0 && line
[read
- 1] == '\n') {
2713 unsunder(line
, read
);
2714 update_history(history
, line
);
2716 history
= &replace_history
;
2726 /* Write the lines of a history list, starting with the line at h, to
2727 * the open file at hist. Return TRUE if the write succeeded, and FALSE
2729 bool writehist(FILE *hist
, filestruct
*h
)
2733 /* Write a history list from the oldest entry to the newest. Assume
2734 * the last history entry is a blank line. */
2735 for (p
= h
; p
!= NULL
; p
= p
->next
) {
2736 size_t p_len
= strlen(p
->data
);
2740 if (fwrite(p
->data
, sizeof(char), p_len
, hist
) < p_len
||
2741 putc('\n', hist
) == EOF
)
2748 /* Save histories to ~/.nano_history. */
2749 void save_history(void)
2753 /* Don't save unchanged or empty histories. */
2754 if (!history_has_changed() || (searchbot
->lineno
== 1 &&
2755 replacebot
->lineno
== 1))
2758 nanohist
= histfilename();
2760 if (nanohist
!= NULL
) {
2761 FILE *hist
= fopen(nanohist
, "wb");
2764 rcfile_error(N_("Error writing %s: %s"), nanohist
,
2767 /* Make sure no one else can read from or write to the
2769 chmod(nanohist
, S_IRUSR
| S_IWUSR
);
2771 if (!writehist(hist
, searchage
) || !writehist(hist
,
2773 rcfile_error(N_("Error writing %s: %s"), nanohist
,
2782 #endif /* !NANO_TINY && ENABLE_NANORC */