blob: 866bbbcf59dd49b197216e3753735de46454af64 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettabceb1b22000-06-19 04:22:15 +00002/**************************************************************************
3 * files.c *
4 * *
5 * Copyright (C) 1999 Chris Allegretta *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 1, or (at your option) *
9 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettabceb1b22000-06-19 04:22:15 +000024#include <stdlib.h>
25#include <string.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <fcntl.h>
31#include <errno.h>
Chris Allegretta04d848e2000-11-05 17:54:41 +000032#include <ctype.h>
33#include <dirent.h>
Chris Allegrettaee733e62001-01-22 22:17:08 +000034#include <pwd.h>
Chris Allegrettabceb1b22000-06-19 04:22:15 +000035
Chris Allegrettabceb1b22000-06-19 04:22:15 +000036#include "proto.h"
37#include "nano.h"
Chris Allegretta4da1fc62000-06-21 03:00:43 +000038
Chris Allegrettabceb1b22000-06-19 04:22:15 +000039#ifndef NANO_SMALL
40#include <libintl.h>
41#define _(string) gettext(string)
42#else
43#define _(string) (string)
44#endif
45
46/* Load file into edit buffer - takes data from file struct */
47void load_file(void)
48{
49 current = fileage;
50 wmove(edit, current_y, current_x);
51}
52
53/* What happens when there is no file to open? aiee! */
54void new_file(void)
55{
56 fileage = nmalloc(sizeof(filestruct));
Chris Allegretta88b09152001-05-17 11:35:43 +000057 fileage->data = charalloc(1);
Chris Allegrettabceb1b22000-06-19 04:22:15 +000058 strcpy(fileage->data, "");
59 fileage->prev = NULL;
60 fileage->next = NULL;
61 fileage->lineno = 1;
62 filebot = fileage;
63 edittop = fileage;
64 editbot = fileage;
65 current = fileage;
66 totlines = 1;
67 UNSET(VIEW_MODE);
68}
69
70
71int read_byte(int fd, char *filename, char *input)
72{
73 static char buf[BUFSIZ];
74 static int index = 0;
75 static int size = 0;
76
77 if (index == size) {
78 index = 0;
79 size = read(fd, buf, BUFSIZ);
80 if (size == -1) {
81 clear();
82 refresh();
83 resetty();
84 endwin();
85 perror(filename);
86 }
87 if (!size)
88 return 0;
89 }
90 *input = buf[index++];
91 return 1;
92}
93
94filestruct *read_line(char *buf, filestruct * prev, int *line1ins)
95{
96 filestruct *fileptr;
97
98 fileptr = nmalloc(sizeof(filestruct));
Chris Allegretta88b09152001-05-17 11:35:43 +000099 fileptr->data = charalloc(strlen(buf) + 2);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000100 strcpy(fileptr->data, buf);
101
102 if (*line1ins) {
103 /* Special case, insert with cursor on 1st line. */
104 fileptr->prev = NULL;
105 fileptr->next = fileage;
106 fileptr->lineno = 1;
107 *line1ins = 0;
108 /* If we're inserting into the first line of the file, then
109 we want to make sure that our edit buffer stays on the
110 first line (and that fileage stays up to date!) */
111 fileage = fileptr;
112 edittop = fileptr;
113 } else if (fileage == NULL) {
114 fileage = fileptr;
115 fileage->lineno = 1;
116 fileage->next = fileage->prev = NULL;
117 fileptr = filebot = fileage;
118 } else if (prev) {
119 fileptr->prev = prev;
120 fileptr->next = NULL;
121 fileptr->lineno = prev->lineno + 1;
122 prev->next = fileptr;
123 } else {
124 die(_("read_line: not on first line and prev is NULL"));
125 }
126
127 return fileptr;
128}
129
130
131int read_file(int fd, char *filename)
132{
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000133 long size, num_lines = 0, linetemp = 0;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000134 char input[2]; /* buffer */
135 char *buf;
136 long i = 0, bufx = 128;
137 filestruct *fileptr = current, *tmp = NULL;
138 int line1ins = 0;
139
Chris Allegretta88b09152001-05-17 11:35:43 +0000140 buf = charalloc(bufx);
Chris Allegretta8f6c0692000-07-19 01:16:18 +0000141 buf[0] = '\0';
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000142
143 if (fileptr != NULL && fileptr->prev != NULL) {
144 fileptr = fileptr->prev;
145 tmp = fileptr;
146 } else if (fileptr != NULL && fileptr->prev == NULL) {
147 tmp = fileage;
148 current = fileage;
149 line1ins = 1;
150 }
151 input[1] = 0;
152 /* Read the entire file into file struct */
153 while ((size = read_byte(fd, filename, input)) > 0) {
154 linetemp = 0;
155 if (input[0] == '\n') {
156 fileptr = read_line(buf, fileptr, &line1ins);
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000157 num_lines++;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000158 buf[0] = 0;
159 i = 0;
160 } else {
161 /* Now we allocate a bigger buffer 128 characters at a time.
162 If we allocate a lot of space for one line, we may indeed
163 have to use a buffer this big later on, so we don't
Chris Allegretta88520c92001-05-05 17:45:54 +0000164 decrease it at all. We do free it at the end, though. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000165
166 if (i >= bufx - 1) {
167 buf = nrealloc(buf, bufx + 128);
168 bufx += 128;
169 }
170 buf[i] = input[0];
171 buf[i + 1] = 0;
172 i++;
173 }
174 totsize += size;
175 }
176
177 /* Did we not get a newline but still have stuff to do? */
178 if (buf[0]) {
179 fileptr = read_line(buf, fileptr, &line1ins);
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000180 num_lines++;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000181 buf[0] = 0;
182 }
183 /* Did we even GET a file? */
Chris Allegretta9956e532000-11-26 02:09:53 +0000184 if (totsize == 0 || fileptr == NULL) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000185 new_file();
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000186 statusbar(_("Read %d lines"), num_lines);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000187 return 1;
188 }
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000189
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000190 if (current != NULL) {
191 fileptr->next = current;
192 current->prev = fileptr;
193 renumber(current);
194 current_x = 0;
195 placewewant = 0;
196 } else if (fileptr->next == NULL) {
197 filebot = fileptr;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000198 new_magicline();
Chris Allegretta321590a2000-12-10 06:03:40 +0000199 totsize--;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000200
201 /* Update the edit buffer */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000202 load_file();
203 }
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000204 statusbar(_("Read %d lines"), num_lines);
205 totlines += num_lines;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000206
207 free(buf);
208 close(fd);
209
210 return 1;
211}
212
213/* Open the file (and decide if it exists) */
214int open_file(char *filename, int insert, int quiet)
215{
216 int fd;
217 struct stat fileinfo;
218
219 if (!strcmp(filename, "") || stat(filename, &fileinfo) == -1) {
220 if (insert) {
221 if (!quiet)
222 statusbar(_("\"%s\" not found"), filename);
223 return -1;
224 } else {
225 /* We have a new file */
226 statusbar(_("New File"));
227 new_file();
228 }
229 } else if ((fd = open(filename, O_RDONLY)) == -1) {
230 if (!quiet)
231 statusbar("%s: %s", strerror(errno), filename);
Chris Allegretta3a7c0be2000-12-18 01:09:07 +0000232 if (!insert)
233 new_file();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000234 return -1;
235 } else { /* File is A-OK */
Chris Allegretta7960dcf2000-12-13 15:01:29 +0000236 if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
237 S_ISBLK(fileinfo.st_mode)) {
238 if (S_ISDIR(fileinfo.st_mode))
239 statusbar(_("File \"%s\" is a directory"), filename);
240 else
241 /* Don't open character or block files. Sorry, /dev/sndstat! */
242 statusbar(_("File \"%s\" is a device file"), filename);
243
Chris Allegrettaf45c18d2000-09-16 05:25:06 +0000244 if (!insert)
245 new_file();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000246 return -1;
247 }
248 if (!quiet)
249 statusbar(_("Reading File"));
250 read_file(fd, filename);
251 }
252
253 return 1;
254}
255
256int do_insertfile(void)
257{
258 int i;
Chris Allegretta25f4e582000-11-25 05:03:20 +0000259 char *realname = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000260
261 wrap_reset();
Chris Allegretta6fe61492001-05-21 12:56:25 +0000262
263#ifndef DISABLE_MOUSE
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000264 currshortcut = insertfile_list;
265 currslen = INSERTFILE_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000266#endif
267
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000268 i = statusq(1, insertfile_list, INSERTFILE_LIST_LEN, "",
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000269 _("File to insert [from ./] "));
270 if (i != -1) {
271
272#ifdef DEBUG
273 fprintf(stderr, "filename is %s", answer);
274#endif
275
Rocco Corsi06aca1c2001-01-11 05:30:31 +0000276#ifndef DISABLE_TABCOMP
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000277 realname = real_dir_from_tilde(answer);
Chris Allegretta09a80842000-11-30 02:31:13 +0000278#else
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000279 realname = mallocstrcpy(realname, answer);
Chris Allegretta09a80842000-11-30 02:31:13 +0000280#endif
Chris Allegretta25f4e582000-11-25 05:03:20 +0000281
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000282#ifndef DISABLE_BROWSER
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000283 if (i == NANO_TOFILES_KEY) {
Chris Allegretta150469a2001-01-05 21:13:14 +0000284
285 char *tmp = do_browse_from(realname);
Chris Allegretta6fe61492001-05-21 12:56:25 +0000286#ifndef DISABLE_MOUSE
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000287 currshortcut = insertfile_list;
288 currslen = INSERTFILE_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000289#endif
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000290
Rocco Corsi06aca1c2001-01-11 05:30:31 +0000291#ifdef DISABLE_TABCOMP
Chris Allegretta544347c2001-01-05 14:31:52 +0000292 realname = NULL;
Chris Allegretta123e5e62001-01-04 22:05:47 +0000293#endif
294 if (tmp != NULL)
Chris Allegretta544347c2001-01-05 14:31:52 +0000295 realname = mallocstrcpy(realname, tmp);
Chris Allegretta123e5e62001-01-04 22:05:47 +0000296 else
Chris Allegrettafe415842001-01-04 05:08:37 +0000297 return do_insertfile();
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000298 }
299#endif
300
Chris Allegretta25f4e582000-11-25 05:03:20 +0000301 i = open_file(realname, 1, 0);
302 free(realname);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000303
304 dump_buffer(fileage);
305 set_modified();
306
307 /* Here we want to rebuild the edit window */
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000308 fix_editbot();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000309
Chris Allegretta88520c92001-05-05 17:45:54 +0000310 /* If we've gone off the bottom, recenter; otherwise, just redraw */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000311 if (current->lineno > editbot->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000312 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000313 else
314 edit_refresh();
315
316 UNSET(KEEP_CUTBUFFER);
317 display_main_list();
318 return i;
319 } else {
320 statusbar(_("Cancelled"));
321 UNSET(KEEP_CUTBUFFER);
322 display_main_list();
323 return 0;
324 }
325}
326
327/*
328 * Write a file out. If tmp is nonzero, we set the umask to 0600,
Chris Allegretta88520c92001-05-05 17:45:54 +0000329 * we don't set the global variable filename to its name, and don't
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000330 * print out how many lines we wrote on the statusbar.
331 *
Chris Allegretta49805172001-03-28 02:14:28 +0000332 * tmp means we are writing a tmp file in a secure fashion. We use
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000333 * it when spell checking or dumping the file on an error.
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000334 *
335 * append means, not surprisingly, whether we are appending instead
336 * of overwriting.
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000337 */
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000338int write_file(char *name, int tmp, int append)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000339{
340 long size, lineswritten = 0;
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000341 static char *buf = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000342 filestruct *fileptr;
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000343 int fd, mask = 0, realexists, anyexists;
Chris Allegretta7960dcf2000-12-13 15:01:29 +0000344 struct stat st, lst;
Chris Allegretta0f5dfef2000-11-24 14:02:57 +0000345 static char *realname = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000346
347 if (!strcmp(name, "")) {
348 statusbar(_("Cancelled"));
349 return -1;
350 }
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000351 titlebar(NULL);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000352 fileptr = fileage;
Chris Allegretta0f5dfef2000-11-24 14:02:57 +0000353
354 if (realname != NULL)
355 free(realname);
356
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000357 if (buf != NULL)
358 free(buf);
359
Rocco Corsi06aca1c2001-01-11 05:30:31 +0000360#ifndef DISABLE_TABCOMP
Chris Allegrettabe77c612000-11-24 14:00:16 +0000361 realname = real_dir_from_tilde(name);
362#else
363 realname = mallocstrcpy(realname, name);
364#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000365
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000366 /* Save the state of file at the end of the symlink (if there is one) */
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000367 realexists = stat(realname, &st);
368
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000369 /* Stat the link itself for the check... */
370 anyexists = lstat(realname, &lst);
Chris Allegrettaacb62342000-07-21 22:42:46 +0000371
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000372 /* New case: if the file exists, just give up */
373 if (tmp && anyexists != -1)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000374 return -1;
Chris Allegrettab5bb24c2000-12-06 00:57:54 +0000375 /* NOTE: If you change this statement, you MUST CHANGE the if
Chris Allegretta544d9b02000-12-11 02:47:13 +0000376 statement below (that says:
377 if (realexists == -1 || tmp || (!ISSET(FOLLOW_SYMLINKS) &&
378 S_ISLNK(lst.st_mode))) {
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000379 to reflect whether or not to link/unlink/rename the file */
380 else if (ISSET(FOLLOW_SYMLINKS) || !S_ISLNK(lst.st_mode) || tmp) {
Chris Allegretta33084392000-12-09 22:50:38 +0000381 /* Use O_EXCL if tmp == 1. This is now copied from joe, because
Chris Allegrettaf5977772000-12-09 23:58:41 +0000382 wiggy says so *shrug*. */
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000383 if (append)
384 fd = open(realname, O_WRONLY | O_APPEND, (S_IRUSR|S_IWUSR));
385 else if (tmp)
Chris Allegrettaf5977772000-12-09 23:58:41 +0000386 fd = open(realname, O_WRONLY | O_CREAT | O_EXCL, (S_IRUSR|S_IWUSR));
387 else
388 fd = open(realname, O_WRONLY | O_CREAT | O_TRUNC, (S_IRUSR|S_IWUSR));
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000389
390 /* First, just give up if we couldn't even open the file */
Chris Allegretta59828492000-12-04 03:31:39 +0000391 if (fd == -1) {
Chris Allegretta20c131c2000-12-04 04:20:09 +0000392 if (!tmp && ISSET(TEMP_OPT)) {
Chris Allegrettaa299b032000-07-14 02:44:02 +0000393 UNSET(TEMP_OPT);
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000394 return do_writeout(filename, 1, 0);
Chris Allegrettaa299b032000-07-14 02:44:02 +0000395 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000396 statusbar(_("Could not open file for writing: %s"),
397 strerror(errno));
398 return -1;
399 }
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000400
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000401 }
402 /* Don't follow symlink. Create new file. */
403 else {
Chris Allegretta88b09152001-05-17 11:35:43 +0000404 buf = charalloc(strlen(realname) + 8);
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000405 strncpy(buf, realname, strlen(realname)+1);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000406 strcat(buf, ".XXXXXX");
407 if ((fd = mkstemp(buf)) == -1) {
Chris Allegrettaa299b032000-07-14 02:44:02 +0000408 if (ISSET(TEMP_OPT)) {
409 UNSET(TEMP_OPT);
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000410 return do_writeout(filename, 1, 0);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000411 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000412 statusbar(_("Could not open file for writing: %s"),
413 strerror(errno));
414 return -1;
415 }
416 }
417
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000418 dump_buffer(fileage);
419 while (fileptr != NULL && fileptr->next != NULL) {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000420 /* Next line is so we discount the "magic line" */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000421 if (filebot == fileptr && fileptr->data[0] == '\0')
422 break;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000423
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000424 size = write(fd, fileptr->data, strlen(fileptr->data));
425 if (size == -1) {
426 statusbar(_("Could not open file for writing: %s"),
427 strerror(errno));
428 return -1;
429 } else {
430#ifdef DEBUG
431 fprintf(stderr, _("Wrote >%s\n"), fileptr->data);
432#endif
433 }
434 write(fd, "\n", 1);
435
436 fileptr = fileptr->next;
437 lineswritten++;
438 }
439
440 if (fileptr != NULL) {
441 size = write(fd, fileptr->data, strlen(fileptr->data));
442 if (size == -1) {
443 statusbar(_("Could not open file for writing: %s"),
444 strerror(errno));
445 return -1;
446 } else if (size > 0) {
447 size = write(fd, "\n", 1);
448 if (size == -1) {
449 statusbar(_("Could not open file for writing: %s"),
450 strerror(errno));
451 return -1;
452 }
453 }
454 }
455
456
457 if (close(fd) == -1) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000458 statusbar(_("Could not close %s: %s"), realname, strerror(errno));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000459 unlink(buf);
460 return -1;
461 }
462
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000463 if (realexists == -1 || tmp ||
464 (!ISSET(FOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000465
Chris Allegretta88520c92001-05-05 17:45:54 +0000466 /* Use default umask as file permissions if file is a new file. */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000467 mask = umask(0);
468 umask(mask);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000469
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000470 if (tmp) /* We don't want anyone reading our temporary file! */
471 mask = 0600;
472 else
473 mask = 0666 & ~mask;
474 } else
Chris Allegrettada13f0b2000-12-06 05:59:31 +0000475 /* Use permissions from file we are overwriting. */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000476 mask = st.st_mode;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000477
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000478 if (!tmp && (!ISSET(FOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000479 if (unlink(realname) == -1) {
480 if (errno != ENOENT) {
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000481 statusbar(_("Could not open %s for writing: %s"),
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000482 realname, strerror(errno));
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000483 unlink(buf);
484 return -1;
485 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000486 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000487 if (link(buf, realname) != -1)
488 unlink(buf);
489 else if (errno != EPERM) {
490 statusbar(_("Could not open %s for writing: %s"),
491 name, strerror(errno));
492 unlink(buf);
493 return -1;
494 } else if (rename(buf, realname) == -1) { /* Try a rename?? */
495 statusbar(_("Could not open %s for writing: %s"),
496 realname, strerror(errno));
497 unlink(buf);
498 return -1;
499 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000500 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000501 if (chmod(realname, mask) == -1)
502 statusbar(_("Could not set permissions %o on %s: %s"),
503 mask, realname, strerror(errno));
504
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000505 if (!tmp) {
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000506 filename = mallocstrcpy(filename, realname);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000507 statusbar(_("Wrote %d lines"), lineswritten);
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000508 UNSET(MODIFIED);
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000509 titlebar(NULL);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000510 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000511 return 1;
512}
513
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000514int do_writeout(char *path, int exiting, int append)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000515{
516 int i = 0;
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000517
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000518#ifdef NANO_EXTRA
519 static int did_cred = 0;
520#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000521
Chris Allegretta6fe61492001-05-21 12:56:25 +0000522#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000523 currshortcut = writefile_list;
524 currslen = WRITEFILE_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000525#endif
526
Chris Allegrettae1ebaf32001-01-07 05:50:36 +0000527 answer = mallocstrcpy(answer, path);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000528
Chris Allegretta962c3c92000-07-24 21:52:17 +0000529 if ((exiting) && (ISSET(TEMP_OPT))) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000530 if (filename[0]) {
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000531 i = write_file(answer, 0, 0);
Chris Allegretta962c3c92000-07-24 21:52:17 +0000532 display_main_list();
533 return i;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000534 } else {
Chris Allegretta461b2a92000-07-24 22:05:18 +0000535 UNSET(TEMP_OPT);
536 do_exit();
537
538 /* They cancelled, abort quit */
539 return -1;
Chris Allegretta962c3c92000-07-24 21:52:17 +0000540 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000541 }
542
543 while (1) {
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000544 if (ISSET(MARK_ISSET) && !exiting)
Chris Allegrettad21195f2001-06-05 22:57:43 +0000545 i = statusq(1, writefile_list, WRITEFILE_LIST_LEN, "",
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000546 _("%s Selection to File"), append ? _("Append") : _("Write"));
547 else
548 i = statusq(1, writefile_list, WRITEFILE_LIST_LEN, answer,
549 _("File Name to %s"), append ? _("Append") : _("Write"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000550
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000551 if (i != -1) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000552
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000553#ifndef DISABLE_BROWSER
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000554 if (i == NANO_TOFILES_KEY) {
Chris Allegretta150469a2001-01-05 21:13:14 +0000555
556 char *tmp = do_browse_from(answer);
Chris Allegretta6fe61492001-05-21 12:56:25 +0000557
558#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000559 currshortcut = writefile_list;
560 currslen = WRITEFILE_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000561#endif
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000562
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000563 if (tmp != NULL) {
Chris Allegretta544347c2001-01-05 14:31:52 +0000564 answer = mallocstrcpy(answer, tmp);
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000565 } else
566 return do_writeout(answer, exiting, append);
567 } else
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000568#endif
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000569 if (i == NANO_APPEND_KEY)
570 return(do_writeout(answer, exiting, 1 - append));
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000571
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000572#ifdef DEBUG
573 fprintf(stderr, _("filename is %s"), answer);
574#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000575
576#ifdef NANO_EXTRA
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000577 if (exiting && !ISSET(TEMP_OPT) && !strcasecmp(answer, "zzy")
578 && !did_cred) {
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000579 do_credits();
580 did_cred = 1;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000581 return -1;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000582 }
583#endif
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000584 if (!append && strcmp(answer, filename)) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000585 struct stat st;
586 if (!stat(answer, &st)) {
587 i = do_yesno(0, 0, _("File exists, OVERWRITE ?"));
588
589 if (!i || (i == -1))
590 continue;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000591 }
592 }
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000593#ifndef NANO_SMALL
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000594
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000595 /* Here's where we allow the selected text to be written to
596 a separate file. */
597 if (ISSET(MARK_ISSET) && !exiting) {
598 char *backup = NULL;
599 filestruct *fileagebak = fileage;
600 filestruct *filebotbak = filebot;
601 filestruct *cutback = cutbuffer;
602 int oldmod = 0;
603
604 /* Okay, since write_file changes the filename, back it up */
605 backup = mallocstrcpy(backup, filename);
606 if (ISSET(MODIFIED))
607 oldmod = 1;
608
609 /* Now, non-destructively add the marked text to the
610 cutbuffer, and write the file out using the cutbuffer ;) */
611 if (current->lineno < mark_beginbuf->lineno)
612 cut_marked_segment(current, current_x, mark_beginbuf,
613 mark_beginx, 0);
614 else
615 cut_marked_segment(mark_beginbuf, mark_beginx, current,
616 current_x, 0);
617
618 fileage = cutbuffer;
619 for (filebot = cutbuffer; filebot->next != NULL;
620 filebot = filebot->next)
621 ;
622 i = write_file(answer, 0, append);
623
624 /* Now restore everything */
625 backup = mallocstrcpy(filename, backup);
626 fileage = fileagebak;
627 filebot = filebotbak;
628 cutbuffer = cutback;
629 if (oldmod)
630 set_modified();
631 } else
632#endif
633 i = write_file(answer, 0, append);
634
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000635 display_main_list();
636 return i;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000637 } else {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000638 statusbar(_("Cancelled"));
639 display_main_list();
640 return 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000641 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000642 }
643}
644
645int do_writeout_void(void)
646{
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000647 return do_writeout(filename, 0, 0);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000648}
Chris Allegretta04d848e2000-11-05 17:54:41 +0000649
Rocco Corsi06aca1c2001-01-11 05:30:31 +0000650#ifndef DISABLE_TABCOMP
Chris Allegrettabe77c612000-11-24 14:00:16 +0000651
652/* Return a malloc()ed string containing the actual directory, used
653 * to convert ~user and ~/ notation...
654 */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000655char *real_dir_from_tilde(char *buf)
Chris Allegrettabe77c612000-11-24 14:00:16 +0000656{
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000657 char *dirtmp = NULL, *find_user = NULL;
658 int i = 1;
Chris Allegrettaee733e62001-01-22 22:17:08 +0000659 struct passwd *userdata;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000660
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000661 /* set a default value for dirtmp, in the case user home dir not found */
662 dirtmp = mallocstrcpy(dirtmp, buf);
663
Chris Allegrettabe77c612000-11-24 14:00:16 +0000664 if (buf[0] == '~') {
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000665 if (buf[1] == 0 || buf[1] == '/') {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000666 if (getenv("HOME") != NULL) {
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000667
668 free(dirtmp);
Chris Allegretta88b09152001-05-17 11:35:43 +0000669 dirtmp = charalloc(strlen(buf) + 2 + strlen(getenv("HOME")));
Chris Allegrettabe77c612000-11-24 14:00:16 +0000670
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000671 sprintf(dirtmp, "%s%s", getenv("HOME"), &buf[1]);
Chris Allegrettabf692612001-01-08 16:59:19 +0000672
Chris Allegrettabe77c612000-11-24 14:00:16 +0000673 }
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000674 }
675 else {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000676
Chris Allegretta88520c92001-05-05 17:45:54 +0000677 /* Figure how how much of the str we need to compare */
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000678 for (i = 1; buf[i] != '/' && buf[i] != 0; i++)
679 ;
680
681 find_user = mallocstrcpy(find_user, &buf[1]);
682 find_user[i - 1] = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +0000683
Chris Allegrettaee733e62001-01-22 22:17:08 +0000684 for (userdata = getpwent(); userdata != NULL &&
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000685 strcmp(userdata->pw_name, find_user);
Chris Allegrettaee733e62001-01-22 22:17:08 +0000686 userdata = getpwent());
Chris Allegretta04fec912000-11-25 04:43:43 +0000687
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000688 free(find_user);
Chris Allegretta04fec912000-11-25 04:43:43 +0000689
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000690 if (userdata != NULL) { /* User found */
Chris Allegretta04fec912000-11-25 04:43:43 +0000691
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000692 free(dirtmp);
Chris Allegretta88b09152001-05-17 11:35:43 +0000693 dirtmp = charalloc(strlen(buf) + 2 + strlen(userdata->pw_dir));
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000694 sprintf(dirtmp, "%s%s", userdata->pw_dir, &buf[i]);
695
696 }
697
Chris Allegrettaee733e62001-01-22 22:17:08 +0000698 endpwent();
Chris Allegrettabe77c612000-11-24 14:00:16 +0000699 }
Chris Allegrettae5e4d492001-01-23 03:09:15 +0000700 }
Chris Allegrettabe77c612000-11-24 14:00:16 +0000701
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000702 return dirtmp;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000703}
704
705/* Tack a slash onto the string we're completing if it's a directory */
Chris Allegretta04fec912000-11-25 04:43:43 +0000706int append_slash_if_dir(char *buf, int *lastWasTab, int *place)
Chris Allegrettabe77c612000-11-24 14:00:16 +0000707{
708 char *dirptr;
709 struct stat fileinfo;
Chris Allegretta04fec912000-11-25 04:43:43 +0000710 int ret = 0;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000711
712 dirptr = real_dir_from_tilde(buf);
713
714 if (stat(dirptr, &fileinfo) == -1)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000715 ret = 0;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000716 else if (S_ISDIR(fileinfo.st_mode)) {
717 strncat(buf, "/", 1);
718 *place += 1;
719 /* now we start over again with # of tabs so far */
720 *lastWasTab = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +0000721 ret = 1;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000722 }
723
724 if (dirptr != buf)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000725 free(dirptr);
Chris Allegretta04fec912000-11-25 04:43:43 +0000726
727 return ret;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000728}
Chris Allegretta04d848e2000-11-05 17:54:41 +0000729
730/*
731 * These functions (username_tab_completion, cwd_tab_completion, and
732 * input_tab were taken from busybox 0.46 (cmdedit.c). Here is the notice
733 * from that file:
734 *
735 * Termios command line History and Editting, originally
736 * intended for NetBSD sh (ash)
737 * Copyright (c) 1999
738 * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
739 * Etc: Dave Cinege <dcinege@psychosis.com>
740 * Majorly adjusted/re-written for busybox:
741 * Erik Andersen <andersee@debian.org>
742 *
743 * You may use this code as you wish, so long as the original author(s)
744 * are attributed in any redistributions of the source code.
745 * This code is 'as is' with no warranty.
746 * This code may safely be consumed by a BSD or GPL license.
747 */
748
749char **username_tab_completion(char *buf, int *num_matches)
750{
Chris Allegretta2c2c5f22001-01-23 03:27:31 +0000751 char **matches = (char **) NULL;
Chris Allegretta8d9b11a2001-01-19 04:17:24 +0000752 char *matchline = NULL;
Chris Allegretta2c2c5f22001-01-23 03:27:31 +0000753 struct passwd *userdata;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000754
Chris Allegretta8d9b11a2001-01-19 04:17:24 +0000755 *num_matches = 0;
Rocco Corsi8b6cccc2001-01-02 06:21:07 +0000756 matches = nmalloc(BUFSIZ * sizeof(char *));
Chris Allegretta8d9b11a2001-01-19 04:17:24 +0000757
Chris Allegrettabe77c612000-11-24 14:00:16 +0000758 strcat(buf, "*");
Chris Allegretta8d9b11a2001-01-19 04:17:24 +0000759
Chris Allegretta2c2c5f22001-01-23 03:27:31 +0000760 while ((userdata = getpwent()) != NULL) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000761
Chris Allegretta2c2c5f22001-01-23 03:27:31 +0000762 if (check_wildcard_match(userdata->pw_name, &buf[1]) == TRUE) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000763
Chris Allegrettabe77c612000-11-24 14:00:16 +0000764 /* Cool, found a match. Add it to the list
765 * This makes a lot more sense to me (Chris) this way...
766 */
Chris Allegretta8d9b11a2001-01-19 04:17:24 +0000767
Chris Allegretta88b09152001-05-17 11:35:43 +0000768 matchline = charalloc(strlen(userdata->pw_name) + 2);
Chris Allegretta2c2c5f22001-01-23 03:27:31 +0000769 sprintf(matchline, "~%s", userdata->pw_name);
770 matches[*num_matches] = matchline;
771 ++*num_matches;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000772
Chris Allegretta2c2c5f22001-01-23 03:27:31 +0000773 /* If there's no more room, bail out */
774 if (*num_matches == BUFSIZ)
775 break;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000776 }
Chris Allegretta2c2c5f22001-01-23 03:27:31 +0000777 }
778 endpwent();
Chris Allegretta8d9b11a2001-01-19 04:17:24 +0000779
Chris Allegretta04d848e2000-11-05 17:54:41 +0000780 return (matches);
781}
782
783/* This was originally called exe_n_cwd_tab_completion, but we're not
784 worried about executables, only filenames :> */
785
786char **cwd_tab_completion(char *buf, int *num_matches)
787{
Chris Allegrettabe77c612000-11-24 14:00:16 +0000788 char *dirName, *dirtmp = NULL, *tmp = NULL, *tmp2 = NULL;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000789 char **matches = (char **) NULL;
790 DIR *dir;
791 struct dirent *next;
792
Rocco Corsi8b6cccc2001-01-02 06:21:07 +0000793 matches = nmalloc(BUFSIZ * sizeof(char *));
Chris Allegretta04d848e2000-11-05 17:54:41 +0000794
795 /* Stick a wildcard onto the buf, for later use */
796 strcat(buf, "*");
797
Chris Allegretta2c975222000-11-15 01:25:42 +0000798 /* Okie, if there's a / in the buffer, strip out the directory part */
Chris Allegretta04d848e2000-11-05 17:54:41 +0000799 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegretta88b09152001-05-17 11:35:43 +0000800 dirName = charalloc(strlen(buf) + 1);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000801 tmp = buf + strlen(buf);
802 while (*tmp != '/' && tmp != buf)
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000803 tmp--;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000804
Chris Allegretta04d848e2000-11-05 17:54:41 +0000805 tmp++;
806
Chris Allegretta442f2c52000-11-14 17:46:06 +0000807 strncpy(dirName, buf, tmp - buf + 1);
808 dirName[tmp - buf] = 0;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000809
Chris Allegretta04d848e2000-11-05 17:54:41 +0000810 } else {
Chris Allegretta90d30742001-04-03 01:02:38 +0000811
812#ifdef PATH_MAX
813 if ((dirName = getcwd(NULL, PATH_MAX+1)) == NULL)
814#else
Chris Allegretta88520c92001-05-05 17:45:54 +0000815 /* The better, but apparently segfault-causing way */
Chris Allegretta04d848e2000-11-05 17:54:41 +0000816 if ((dirName = getcwd(NULL, 0)) == NULL)
Chris Allegretta90d30742001-04-03 01:02:38 +0000817#endif /* PATH_MAX */
Chris Allegretta04d848e2000-11-05 17:54:41 +0000818 return matches;
819 else
820 tmp = buf;
821 }
822
823#ifdef DEBUG
824 fprintf(stderr, "\nDir = %s\n", dirName);
825 fprintf(stderr, "\nbuf = %s\n", buf);
826 fprintf(stderr, "\ntmp = %s\n", tmp);
827#endif
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000828
Chris Allegrettabe77c612000-11-24 14:00:16 +0000829 dirtmp = real_dir_from_tilde(dirName);
830 free(dirName);
831 dirName = dirtmp;
832
833#ifdef DEBUG
834 fprintf(stderr, "\nDir = %s\n", dirName);
835 fprintf(stderr, "\nbuf = %s\n", buf);
836 fprintf(stderr, "\ntmp = %s\n", tmp);
837#endif
838
839
Chris Allegretta04d848e2000-11-05 17:54:41 +0000840 dir = opendir(dirName);
841 if (!dir) {
842 /* Don't print an error, just shut up and return */
843 *num_matches = 0;
844 beep();
845 return (matches);
846 }
847 while ((next = readdir(dir)) != NULL) {
848
Chris Allegretta04d848e2000-11-05 17:54:41 +0000849#ifdef DEBUG
Chris Allegretta2c975222000-11-15 01:25:42 +0000850 fprintf(stderr, "Comparing \'%s\'\n", next->d_name);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000851#endif
852 /* See if this matches */
853 if (check_wildcard_match(next->d_name, tmp) == TRUE) {
Chris Allegretta7d97ce72000-11-06 04:04:15 +0000854
855 /* Cool, found a match. Add it to the list
856 * This makes a lot more sense to me (Chris) this way...
857 */
858 tmp2 = NULL;
Chris Allegretta88b09152001-05-17 11:35:43 +0000859 tmp2 = charalloc(strlen(next->d_name) + 1);
Chris Allegretta7d97ce72000-11-06 04:04:15 +0000860 strcpy(tmp2, next->d_name);
861 matches[*num_matches] = tmp2;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000862 ++*num_matches;
Chris Allegretta2c975222000-11-15 01:25:42 +0000863
864 /* If there's no more room, bail out */
865 if (*num_matches == BUFSIZ)
866 break;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000867 }
868 }
869
870 return (matches);
871}
872
Chris Allegretta442f2c52000-11-14 17:46:06 +0000873/* This function now has an arg which refers to how much the
Chris Allegretta04d848e2000-11-05 17:54:41 +0000874 * statusbar (place) should be advanced, i.e. the new cursor pos.
875 */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000876char *input_tab(char *buf, int place, int *lastWasTab, int *newplace)
Chris Allegretta04d848e2000-11-05 17:54:41 +0000877{
878 /* Do TAB completion */
Chris Allegrettaec58a992000-11-05 21:54:23 +0000879 static int num_matches = 0, match_matches = 0;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000880 static char **matches = (char **) NULL;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000881 int pos = place, i = 0, col = 0, editline = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +0000882 int longestname = 0, is_dir = 0;
Chris Allegretta3b0d1442000-11-05 21:56:54 +0000883 char *foo;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000884
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000885 if (*lastWasTab == FALSE) {
Chris Allegretta442f2c52000-11-14 17:46:06 +0000886 char *tmp, *copyto, *matchBuf;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000887
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000888 *lastWasTab = 1;
889
Chris Allegretta04d848e2000-11-05 17:54:41 +0000890 /* Make a local copy of the string -- up to the position of the
891 cursor */
Chris Allegrettaa35ec042001-01-15 02:26:12 +0000892 matchBuf = (char *) nmalloc((strlen(buf) + 2) * sizeof(char));
Chris Allegretta40587092001-01-16 04:45:38 +0000893 memset(matchBuf, '\0', (strlen(buf) + 2));
Chris Allegrettae118acc2000-11-06 05:40:03 +0000894
Chris Allegretta04d848e2000-11-05 17:54:41 +0000895 strncpy(matchBuf, buf, place);
896 tmp = matchBuf;
897
898 /* skip any leading white space */
Chris Allegretta63a89d32000-11-18 03:05:50 +0000899 while (*tmp && isspace((int) *tmp))
Chris Allegretta04d848e2000-11-05 17:54:41 +0000900 ++tmp;
901
902 /* Free up any memory already allocated */
903 if (matches != NULL) {
Chris Allegretta442f2c52000-11-14 17:46:06 +0000904 for (i = i; i < num_matches; i++)
905 free(matches[i]);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000906 free(matches);
907 matches = (char **) NULL;
Chris Allegretta7d97ce72000-11-06 04:04:15 +0000908 num_matches = 0;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000909 }
910
911 /* If the word starts with `~' and there is no slash in the word,
912 * then try completing this word as a username. */
913
Chris Allegrettabe77c612000-11-24 14:00:16 +0000914 /* FIXME -- this check is broken! */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000915 if (*tmp == '~' && !strchr(tmp, '/'))
916 matches = username_tab_completion(tmp, &num_matches);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000917
918 /* Try to match everything in the current working directory that
919 * matches. */
920 if (!matches)
921 matches = cwd_tab_completion(tmp, &num_matches);
922
923 /* Don't leak memory */
924 free(matchBuf);
925
Chris Allegretta442f2c52000-11-14 17:46:06 +0000926#ifdef DEBUG
927 fprintf(stderr, "%d matches found...\n", num_matches);
928#endif
Chris Allegretta04d848e2000-11-05 17:54:41 +0000929 /* Did we find exactly one match? */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000930 switch (num_matches) {
Chris Allegrettae118acc2000-11-06 05:40:03 +0000931 case 0:
Chris Allegretta24342432000-11-06 05:41:20 +0000932 blank_edit();
Chris Allegretta2c975222000-11-15 01:25:42 +0000933 wrefresh(edit);
Chris Allegrettae118acc2000-11-06 05:40:03 +0000934 break;
935 case 1:
Chris Allegretta442f2c52000-11-14 17:46:06 +0000936
937 buf = nrealloc(buf, strlen(buf) + strlen(matches[0]) + 1);
938
939 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000940 for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
941 tmp--);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000942 tmp++;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000943 } else
Chris Allegretta442f2c52000-11-14 17:46:06 +0000944 tmp = buf;
945
Chris Allegretta04fec912000-11-25 04:43:43 +0000946 if (!strcmp(tmp, matches[0]))
947 is_dir = append_slash_if_dir(buf, lastWasTab, newplace);
948
949 if (is_dir)
950 break;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000951
952 copyto = tmp;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000953 for (pos = 0; *tmp == matches[0][pos] &&
954 pos <= strlen(matches[0]); pos++)
Chris Allegretta442f2c52000-11-14 17:46:06 +0000955 tmp++;
956
Chris Allegretta2c975222000-11-15 01:25:42 +0000957 /* write out the matched name */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000958 strncpy(copyto, matches[0], strlen(matches[0]) + 1);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000959 *newplace += strlen(matches[0]) - pos;
960
Chris Allegrettabe77c612000-11-24 14:00:16 +0000961 /* Is it a directory? */
962 append_slash_if_dir(buf, lastWasTab, newplace);
963
Chris Allegrettae118acc2000-11-06 05:40:03 +0000964 break;
965 default:
Chris Allegretta88520c92001-05-05 17:45:54 +0000966 /* Check to see if all matches share a beginning, and, if so,
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000967 tack it onto buf and then beep */
Chris Allegrettaec58a992000-11-05 21:54:23 +0000968
Chris Allegretta442f2c52000-11-14 17:46:06 +0000969 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000970 for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
971 tmp--);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000972 tmp++;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000973 } else
Chris Allegretta442f2c52000-11-14 17:46:06 +0000974 tmp = buf;
975
976 for (pos = 0; *tmp == matches[0][pos] && *tmp != 0 &&
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000977 pos <= strlen(matches[0]); pos++)
Chris Allegretta442f2c52000-11-14 17:46:06 +0000978 tmp++;
979
Chris Allegrettaec58a992000-11-05 21:54:23 +0000980 while (1) {
981 match_matches = 0;
982
983 for (i = 0; i < num_matches; i++) {
984 if (matches[i][pos] == 0)
985 break;
986 else if (matches[i][pos] == matches[0][pos])
987 match_matches++;
988 }
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000989 if (match_matches == num_matches &&
990 (i == num_matches || matches[i] != 0)) {
Chris Allegrettaec58a992000-11-05 21:54:23 +0000991 /* All the matches have the same character at pos+1,
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000992 so paste it into buf... */
Chris Allegretta75864952000-11-05 22:48:35 +0000993 buf = nrealloc(buf, strlen(buf) + 2);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000994 strncat(buf, matches[0] + pos, 1);
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000995 *newplace += 1;
Chris Allegrettaec58a992000-11-05 21:54:23 +0000996 pos++;
Chris Allegretta75864952000-11-05 22:48:35 +0000997 } else {
Chris Allegrettaec58a992000-11-05 21:54:23 +0000998 beep();
999 break;
1000 }
1001 }
Chris Allegrettae118acc2000-11-06 05:40:03 +00001002 break;
Chris Allegrettaec58a992000-11-05 21:54:23 +00001003 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001004 } else {
1005 /* Ok -- the last char was a TAB. Since they
1006 * just hit TAB again, print a list of all the
1007 * available choices... */
1008 if (matches && num_matches > 0) {
Chris Allegretta04d848e2000-11-05 17:54:41 +00001009
1010 /* Blank the edit window, and print the matches out there */
1011 blank_edit();
1012 wmove(edit, 0, 0);
1013
Chris Allegrettaec58a992000-11-05 21:54:23 +00001014 editline = 0;
Chris Allegretta2c975222000-11-15 01:25:42 +00001015
Chris Allegrettaec58a992000-11-05 21:54:23 +00001016 /* Figure out the length of the longest filename */
1017 for (i = 0; i < num_matches; i++)
1018 if (strlen(matches[i]) > longestname)
1019 longestname = strlen(matches[i]);
1020
1021 if (longestname > COLS - 1)
1022 longestname = COLS - 1;
1023
Chris Allegretta88b09152001-05-17 11:35:43 +00001024 foo = charalloc(longestname + 5);
Chris Allegretta3b0d1442000-11-05 21:56:54 +00001025
Chris Allegretta04d848e2000-11-05 17:54:41 +00001026 /* Print the list of matches */
1027 for (i = 0, col = 0; i < num_matches; i++) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001028
Chris Allegrettaec58a992000-11-05 21:54:23 +00001029 /* make each filename shown be the same length as the longest
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001030 filename, with two spaces at the end */
Chris Allegrettaec58a992000-11-05 21:54:23 +00001031 snprintf(foo, longestname + 1, matches[i]);
1032 while (strlen(foo) < longestname)
1033 strcat(foo, " ");
1034
1035 strcat(foo, " ");
1036
Chris Allegretta442f2c52000-11-14 17:46:06 +00001037 /* Disable el cursor */
1038 curs_set(0);
Chris Allegretta75864952000-11-05 22:48:35 +00001039 /* now, put the match on the screen */
1040 waddnstr(edit, foo, strlen(foo));
1041 col += strlen(foo);
1042
1043 /* And if the next match isn't going to fit on the
1044 line, move to the next one */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001045 if (col > (COLS - longestname) && matches[i + 1] != NULL) {
Chris Allegrettaec58a992000-11-05 21:54:23 +00001046 editline++;
1047 wmove(edit, editline, 0);
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001048 if (editline == editwinrows - 1) {
1049 waddstr(edit, _("(more)"));
1050 break;
1051 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001052 col = 0;
1053 }
1054 }
Chris Allegretta3b0d1442000-11-05 21:56:54 +00001055 free(foo);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001056 wrefresh(edit);
Chris Allegretta24dd8d62000-11-06 05:45:48 +00001057 } else
1058 beep();
Chris Allegretta04d848e2000-11-05 17:54:41 +00001059
1060 }
1061
1062 edit_refresh();
Chris Allegretta442f2c52000-11-14 17:46:06 +00001063 curs_set(1);
1064 return buf;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001065}
Chris Allegrettabe77c612000-11-24 14:00:16 +00001066#endif
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001067
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001068#ifndef DISABLE_BROWSER
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001069
1070/* Return the stat of the file pointed to by path */
1071struct stat filestat(const char *path) {
1072 struct stat st;
1073
Chris Allegretta0876dc92001-03-28 13:04:08 +00001074 stat(path, &st);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001075 return st;
1076}
1077
1078/* Our sort routine for file listings - sort directories before
1079 * files, and then alphabetically
1080 */
1081int diralphasort(const void *va, const void *vb) {
1082 struct stat file1info, file2info;
1083 char *a = *(char **)va, *b = *(char **)vb;
Chris Allegretta90d30742001-04-03 01:02:38 +00001084 int aisdir, bisdir;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001085
Chris Allegretta90d30742001-04-03 01:02:38 +00001086 aisdir = (stat(a, &file1info) != -1) && S_ISDIR(file1info.st_mode);
1087 bisdir = (stat(b, &file2info) != -1) && S_ISDIR(file2info.st_mode);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001088
Chris Allegretta90d30742001-04-03 01:02:38 +00001089 if (aisdir && !bisdir) return -1;
1090 if (!aisdir && bisdir) return 1;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001091
Chris Allegretta90d30742001-04-03 01:02:38 +00001092#ifdef HAVE_STRCASECMP
1093 return(strcasecmp(a,b));
1094#else
1095 return(strcmp(a,b));
1096#endif
1097
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001098}
1099
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001100
1101/* Initialize the browser code, including the list of files in *path */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001102char **browser_init(char *path, int *longest, int *numents)
1103{
1104 DIR *dir;
1105 struct dirent *next;
1106 char **filelist = (char **) NULL;
1107 int i = 0;
1108
1109 dir = opendir(path);
1110 if (!dir)
1111 return NULL;
1112
1113 *numents = 0;
1114 while ((next = readdir(dir)) != NULL) {
1115 if (!strcmp(next->d_name, "."))
1116 continue;
1117 (*numents)++;
1118 if (strlen(next->d_name) > *longest)
1119 *longest = strlen(next->d_name);
1120 }
1121 rewinddir(dir);
1122 *longest += 10;
1123
1124 filelist = nmalloc(*numents * sizeof (char *));
1125
1126 while ((next = readdir(dir)) != NULL) {
1127 if (!strcmp(next->d_name, "."))
1128 continue;
Chris Allegretta88b09152001-05-17 11:35:43 +00001129 filelist[i] = charalloc(strlen(next->d_name) + strlen(path) + 2);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001130
1131 if (!strcmp(path, "/"))
1132 snprintf(filelist[i], strlen(next->d_name) + strlen(path) + 1,
1133 "%s%s", path, next->d_name);
1134 else
1135 snprintf(filelist[i], strlen(next->d_name) + strlen(path) + 2,
1136 "%s/%s", path, next->d_name);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001137 i++;
1138 }
1139
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001140 if (*longest > COLS - 1)
1141 *longest = COLS - 1;
1142
1143 return filelist;
1144}
1145
Chris Allegretta88520c92001-05-05 17:45:54 +00001146/* Free our malloc()ed memory */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001147void free_charptrarray(char **array, int len)
1148{
1149 int i;
1150
1151 for (i = 0; i < len - 1; i++)
1152 free(array[i]);
1153 free(array);
1154}
1155
Chris Allegretta88520c92001-05-05 17:45:54 +00001156/* only print the last part of a path; isn't there a shell
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001157 command for this? */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001158char *tail(char *foo)
1159{
1160 char *tmp = NULL;
1161
1162 tmp = foo + strlen(foo);
1163 while (*tmp != '/' && tmp != foo)
1164 tmp--;
1165
1166 tmp++;
1167
1168 return tmp;
1169}
1170
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001171/* Strip one dir from the end of a string */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001172void striponedir(char *foo)
1173{
1174 char *tmp = NULL;
1175
1176 /* Don't strip the root dir */
1177 if (!strcmp(foo, "/"))
1178 return;
1179
1180 tmp = foo + strlen(foo);
1181 if (*tmp == '/')
1182 tmp--;
1183
1184 while (*tmp != '/' && tmp != foo)
1185 tmp--;
1186
1187 if (tmp != foo)
1188 *tmp = 0;
1189 else
1190 *(tmp+1) = 0;
1191
1192 return;
1193}
1194
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001195/* Our browser function. inpath is the path to start browsing from */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001196char *do_browser(char *inpath)
1197{
1198 struct stat st;
1199 char *foo, *retval = NULL;
1200 static char *path = NULL;
1201 int numents = 0, i = 0, j = 0, kbinput = 0, longest = 0, abort = 0;
1202 int col = 0, selected = 0, editline = 0, width = 0, filecols = 0;
Chris Allegrettac08f50d2001-01-06 18:12:43 +00001203 int lineno = 0, kb;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001204 char **filelist = (char **) NULL;
Chris Allegretta051fc6e2001-05-05 23:17:36 +00001205#ifndef DISABLE_MOUSE
1206#ifdef NCURSES_MOUSE_VERSION
1207 MEVENT mevent;
1208#endif
1209#endif
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001210
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001211 /* If path isn't the same as inpath, we are being passed a new
1212 dir as an arg. We free it here so it will be copied from
1213 inpath below */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001214 if (path != NULL && strcmp(path, inpath)) {
1215 free(path);
1216 path = NULL;
1217 }
1218
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001219 /* if path doesn't exist, make it so */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001220 if (path == NULL)
1221 path = mallocstrcpy(path, inpath);
1222
1223 filelist = browser_init(path, &longest, &numents);
Chris Allegretta88b09152001-05-17 11:35:43 +00001224 foo = charalloc(longest + 8);
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001225
Chris Allegretta88520c92001-05-05 17:45:54 +00001226 /* Sort the list by directory first, then alphabetically */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001227 qsort(filelist, numents, sizeof(char *), diralphasort);
1228
Chris Allegrettac08f50d2001-01-06 18:12:43 +00001229 kb = keypad_on(edit, 1);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001230 titlebar(path);
1231 bottombars(browser_list, BROWSER_LIST_LEN);
1232 curs_set(0);
1233 wmove(edit, 0, 0);
1234 i = 0;
1235 width = 0;
1236 filecols = 0;
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001237
1238 /* Loop invariant: Microsoft sucks. */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001239 do {
Rocco Corsi12f294c2001-04-14 06:50:24 +00001240 DIR *test_dir;
1241
1242 blank_statusbar_refresh();
1243
Chris Allegretta6fe61492001-05-21 12:56:25 +00001244#ifndef DISABLE_MOUSE
Chris Allegrettab10283c2001-05-07 12:08:37 +00001245 currshortcut = browser_list;
1246 currslen = BROWSER_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +00001247#endif
1248
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001249 editline = 0;
1250 col = 0;
Chris Allegrettab0f52822001-01-04 05:20:23 +00001251
Chris Allegretta88520c92001-05-05 17:45:54 +00001252 /* Compute line number we're on now, so we don't divide by zero later */
Chris Allegrettab0f52822001-01-04 05:20:23 +00001253 if (width == 0)
1254 lineno = selected;
1255 else
1256 lineno = selected / width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001257
1258 switch (kbinput) {
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001259
Chris Allegretta051fc6e2001-05-05 23:17:36 +00001260#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001261#ifdef NCURSES_MOUSE_VERSION
1262 case KEY_MOUSE:
Chris Allegretta051fc6e2001-05-05 23:17:36 +00001263 if (getmouse(&mevent) == ERR)
1264 return retval;
1265
1266 /* If they clicked in the edit window, they probably clicked
1267 on a file */
1268 if (wenclose(edit, mevent.y, mevent.x)) {
1269 int selectedbackup = selected;
1270
1271 mevent.y -= 2;
1272
1273 /* If we're on line 0, don't toy with finding out what
1274 page we're on */
1275 if (lineno / editwinrows == 0)
1276 selected = mevent.y * width + mevent.x / longest;
1277 else
1278 selected = (lineno / editwinrows) * editwinrows * width
1279 + mevent.y * width + mevent.x / longest;
1280
1281 /* If we're off the screen, reset to the last item.
1282 If we clicked where we did last time, select this name! */
Chris Allegrettaf3fde7c2001-05-06 03:02:21 +00001283 if (selected > numents - 1)
Chris Allegretta051fc6e2001-05-05 23:17:36 +00001284 selected = numents - 1;
1285 else if (selectedbackup == selected) {
1286 ungetch('s'); /* Unget the 'select' key */
1287 break;
1288 }
1289 } else /* Must be clicking a shortcut */
1290 do_mouse();
1291
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001292 break;
1293#endif
1294#endif
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001295 case KEY_UP:
1296 case 'u':
1297 if (selected - width >= 0)
1298 selected -= width;
1299 break;
1300 case KEY_LEFT:
1301 case 'l':
1302 if (selected > 0)
1303 selected--;
1304 break;
1305 case KEY_DOWN:
1306 case 'd':
1307 if (selected + width <= numents - 1)
1308 selected += width;
1309 break;
1310 case KEY_RIGHT:
1311 case 'r':
1312 if (selected < numents - 1)
1313 selected++;
1314 break;
1315 case NANO_PREVPAGE_KEY:
Chris Allegretta6e827412001-01-04 04:41:08 +00001316 case NANO_PREVPAGE_FKEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001317 case KEY_PPAGE:
Chris Allegretta8eac3b52001-01-08 21:14:04 +00001318 case '-':
Chris Allegrettab0f52822001-01-04 05:20:23 +00001319
1320 if (lineno % editwinrows == 0) {
Chris Allegretta425a2662001-01-03 15:09:27 +00001321 if (selected - (editwinrows * width) >= 0)
1322 selected -= editwinrows * width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001323 else
1324 selected = 0;
1325 }
1326 else if (selected - (editwinrows +
Chris Allegrettab0f52822001-01-04 05:20:23 +00001327 lineno % editwinrows) * width >= 0)
1328
1329 selected -= (editwinrows + lineno % editwinrows) * width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001330 else
1331 selected = 0;
1332 break;
1333 case NANO_NEXTPAGE_KEY:
Chris Allegretta6e827412001-01-04 04:41:08 +00001334 case NANO_NEXTPAGE_FKEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001335 case KEY_NPAGE:
Chris Allegretta8eac3b52001-01-08 21:14:04 +00001336 case ' ':
Chris Allegrettab0f52822001-01-04 05:20:23 +00001337 if (lineno % editwinrows == 0) {
Chris Allegretta425a2662001-01-03 15:09:27 +00001338 if (selected + (editwinrows * width) <= numents - 1)
1339 selected += editwinrows * width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001340 else
1341 selected = numents - 1;
1342 }
1343 else if (selected + (editwinrows -
Chris Allegrettab0f52822001-01-04 05:20:23 +00001344 lineno % editwinrows) * width <= numents - 1)
1345 selected += (editwinrows - lineno % editwinrows) * width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001346 else
1347 selected = numents - 1;
1348 break;
1349 case KEY_ENTER:
1350 case NANO_CONTROL_M:
Chris Allegrettaba8edea2001-01-04 05:22:46 +00001351 case 's': /* More Pico compatibility */
1352 case 'S':
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001353
1354 /* You can't cd up from / */
Rocco Corsi12f294c2001-04-14 06:50:24 +00001355 if (!strcmp(filelist[selected], "/..") && !strcmp(path, "/")) {
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001356 statusbar(_("Can't move up a directory"));
Rocco Corsi12f294c2001-04-14 06:50:24 +00001357 break;
1358 }
1359
1360 path = mallocstrcpy(path, filelist[selected]);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001361
1362 st = filestat(path);
1363 if (S_ISDIR(st.st_mode)) {
Rocco Corsi12f294c2001-04-14 06:50:24 +00001364 if ((test_dir = opendir(path)) == NULL) {
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001365 /* We can't open this dir for some reason. Complain */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001366 statusbar(_("Can't open \"%s\": %s"), path, strerror(errno));
Rocco Corsi12f294c2001-04-14 06:50:24 +00001367 striponedir(path);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001368 align(&path);
1369 break;
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001370 }
Rocco Corsi12f294c2001-04-14 06:50:24 +00001371 closedir(test_dir);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001372
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001373 if (!strcmp("..", tail(path))) {
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001374 /* They want to go up a level, so strip off .. and the
1375 current dir */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001376 striponedir(path);
1377 striponedir(path);
1378 align(&path);
1379 }
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001380
1381 /* Start over again with the new path value */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001382 return do_browser(path);
1383 } else {
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001384 retval = path;
1385 abort = 1;
1386 }
1387 break;
Rocco Corsi12f294c2001-04-14 06:50:24 +00001388 /* Goto a specific directory */
1389 case 'g': /* Pico compatibility */
1390 case 'G':
1391 case NANO_GOTO_KEY:
1392
1393 curs_set(1);
1394 j = statusq(0, gotodir_list, GOTODIR_LIST_LEN, "", _("Goto Directory"));
1395 bottombars(browser_list, BROWSER_LIST_LEN);
1396 curs_set(0);
1397
1398 if (j < 0) {
1399 statusbar(_("Goto Cancelled"));
1400 break;
1401 }
1402
1403 if (answer[0] != '/') {
1404 char *saveanswer = NULL;
1405
1406 saveanswer = mallocstrcpy(saveanswer, answer);
1407 answer = realloc(answer, strlen(path) + strlen(saveanswer) + 2);
1408 sprintf(answer, "%s/%s", path, saveanswer);
1409 free(saveanswer);
1410 }
1411
1412 if ((test_dir = opendir(answer)) == NULL) {
1413 /* We can't open this dir for some reason. Complain */
1414 statusbar(_("Can't open \"%s\": %s"), answer, strerror(errno));
1415 break;
1416 }
1417 closedir(test_dir);
1418
1419 /* Start over again with the new path value */
1420 path = mallocstrcpy(path, answer);
1421 return do_browser(path);
1422
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001423 /* Stuff we want to abort the browser */
Chris Allegretta8ce24132001-04-30 11:28:46 +00001424 case NANO_CONTROL_C:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001425 case 'q':
1426 case 'Q':
1427 case 'e': /* Pico compatibility, yeech */
1428 case 'E':
Chris Allegretta6e827412001-01-04 04:41:08 +00001429 case NANO_EXIT_FKEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001430 abort = 1;
1431 break;
1432 }
1433 if (abort)
1434 break;
1435
Rocco Corsi12f294c2001-04-14 06:50:24 +00001436 blank_edit();
1437
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001438 if (width)
1439 i = width * editwinrows * ((selected / width) / editwinrows);
1440 else
1441 i = 0;
1442
1443 wmove(edit, 0, 0);
1444 for (j = i; j < numents && editline <= editwinrows - 1; j++) {
1445 filecols++;
1446
1447 strncpy(foo, tail(filelist[j]), strlen(tail(filelist[j])) + 1);
1448 while (strlen(foo) < longest)
1449 strcat(foo, " ");
1450 col += strlen(foo);
1451
1452 /* Put file info in the string also */
Chris Allegretta88520c92001-05-05 17:45:54 +00001453 /* We use lstat here to detect links; then, if we find a
1454 symlink, we examine it via stat() to see if it is a
Chris Allegretta0876dc92001-03-28 13:04:08 +00001455 directory or just a file symlink */
1456 lstat(filelist[j], &st);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001457 if (S_ISDIR(st.st_mode))
1458 strcpy(foo + longest - 5, "(dir)");
1459 else {
Chris Allegretta0876dc92001-03-28 13:04:08 +00001460 if (S_ISLNK(st.st_mode)) {
1461 /* Aha! It's a symlink! Now, is it a dir? If so,
1462 mark it as such */
1463 st = filestat(filelist[j]);
1464 if (S_ISDIR(st.st_mode))
1465 strcpy(foo + longest - 5, "(dir)");
1466 else
1467 strcpy(foo + longest - 2, "--");
Chris Allegretta90d30742001-04-03 01:02:38 +00001468 } else if (st.st_size < (1 << 10)) /* less than 1 K */
1469 sprintf(foo + longest - 7, "%4d B",
Chris Allegrettad4615622001-05-23 21:54:47 +00001470 (int) st.st_size);
Chris Allegretta90d30742001-04-03 01:02:38 +00001471 else if (st.st_size >= (1 << 30)) /* at least 1 gig */
1472 sprintf(foo + longest - 7, "%4d GB",
1473 (int) st.st_size >> 30);
1474 else if (st.st_size >= (1 << 20)) /* at least 1 meg */
1475 sprintf(foo + longest - 7, "%4d MB",
1476 (int) st.st_size >> 20);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001477 else /* Its more than 1 k and less than a meg */
Chris Allegretta90d30742001-04-03 01:02:38 +00001478 sprintf(foo + longest - 7, "%4d KB",
1479 (int) st.st_size >> 10);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001480 }
1481
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001482 /* Hilight the currently selected file/dir */
Chris Allegretta8ce24132001-04-30 11:28:46 +00001483 if (j == selected) {
1484#ifdef ENABLE_COLOR
1485 color_on(edit, COLOR_STATUSBAR);
1486#else
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001487 wattron(edit, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001488
1489#endif
1490 }
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001491 waddnstr(edit, foo, strlen(foo));
Chris Allegretta8ce24132001-04-30 11:28:46 +00001492 if (j == selected) {
1493#ifdef ENABLE_COLOR
1494 color_off(edit, COLOR_STATUSBAR);
1495#else
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001496 wattroff(edit, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00001497#endif
1498 }
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001499
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001500 /* And add some space between the cols */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001501 waddstr(edit, " ");
1502 col += 2;
1503
1504 /* And if the next entry isn't going to fit on the
1505 line, move to the next one */
1506 if (col > (COLS - longest)) {
1507 editline++;
1508 wmove(edit, editline, 0);
1509 col = 0;
1510 if (width == 0)
1511 width = filecols;
1512 }
1513 }
1514 wrefresh(edit);
1515 } while ((kbinput = wgetch(edit)) != NANO_EXIT_KEY);
1516 curs_set(1);
1517 blank_edit();
1518 titlebar(NULL);
1519 edit_refresh();
Chris Allegrettac08f50d2001-01-06 18:12:43 +00001520 kb = keypad_on(edit, kb);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001521
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001522 /* cleanup */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001523 free_charptrarray(filelist, numents);
1524 free(foo);
1525 return retval;
1526}
Chris Allegretta150469a2001-01-05 21:13:14 +00001527
Chris Allegretta88520c92001-05-05 17:45:54 +00001528/* Browser front end, checks to see if inpath has a dir in it and, if so,
Chris Allegretta150469a2001-01-05 21:13:14 +00001529 starts do_browser from there, else from the current dir */
1530char *do_browse_from(char *inpath)
1531{
1532 struct stat st;
1533 char *tmp = NULL;
1534
1535 tmp = mallocstrcpy(tmp, inpath);
1536
Chris Allegretta90d30742001-04-03 01:02:38 +00001537
Chris Allegretta88520c92001-05-05 17:45:54 +00001538 /* If there's no / in the string, we may as well start from . */
Chris Allegretta90d30742001-04-03 01:02:38 +00001539 if (tmp == NULL || *tmp == '\0' || !strstr(tmp, "/")) {
1540#ifdef PATH_MAX
1541 char *from = getcwd(NULL, PATH_MAX+1);
1542#else
Chris Allegretta60c65422001-04-03 14:26:35 +00001543 char *from = getcwd(NULL, 0);
Chris Allegretta90d30742001-04-03 01:02:38 +00001544#endif /* PATH_MAX */
1545 return do_browser(from ? from : "./");
1546 }
Chris Allegretta150469a2001-01-05 21:13:14 +00001547
1548 /* If the string is a directory, pass do_browser that */
1549 st = filestat(tmp);
1550 if (S_ISDIR(st.st_mode))
1551 return do_browser(tmp);
1552
1553 /* Okay, there's a dir in there, but not at the end of the string...
1554 try stripping it off */
1555 striponedir(tmp);
1556 align(&tmp);
1557 return do_browser(tmp);
1558
1559}
1560
1561
1562
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001563#endif
1564