blob: f5bef06910ca8ea6ecc18e3100d19bb78c308633 [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;
Chris Allegretta2d7893d2001-07-11 02:08:33 +000050
Chris Allegretta355fbe52001-07-14 19:32:47 +000051#ifdef ENABLE_MULTIBUFFER
Chris Allegretta2d7893d2001-07-11 02:08:33 +000052 /* add a new entry to the open_files structure, and check for
53 duplicate entries; if a duplicate entry was found, reload the
54 currently open file (it may have been changed during duplicate
55 handling) */
56 if (add_open_file(0, 1) == 2)
57 load_open_file();
58#endif
59
Chris Allegrettabceb1b22000-06-19 04:22:15 +000060 wmove(edit, current_y, current_x);
61}
62
63/* What happens when there is no file to open? aiee! */
64void new_file(void)
65{
66 fileage = nmalloc(sizeof(filestruct));
Chris Allegretta88b09152001-05-17 11:35:43 +000067 fileage->data = charalloc(1);
Chris Allegrettabceb1b22000-06-19 04:22:15 +000068 strcpy(fileage->data, "");
69 fileage->prev = NULL;
70 fileage->next = NULL;
71 fileage->lineno = 1;
72 filebot = fileage;
73 edittop = fileage;
74 editbot = fileage;
75 current = fileage;
76 totlines = 1;
Chris Allegrettae6421972001-07-18 01:03:36 +000077
78#ifdef ENABLE_MULTIBUFFER
79 /* if there aren't any entries in open_files, create the entry for
80 this new file, and, of course, don't bother checking for
81 duplicates; without this, if nano is started without a filename on
82 the command line, a new file with no name will be created, but it
83 will be given no open_files entry, leading to problems later on */
84 if (!open_files)
85 add_open_file(0, 0);
86#endif
87
Chris Allegrettabceb1b22000-06-19 04:22:15 +000088 UNSET(VIEW_MODE);
89}
90
91
92int read_byte(int fd, char *filename, char *input)
93{
94 static char buf[BUFSIZ];
95 static int index = 0;
96 static int size = 0;
97
98 if (index == size) {
99 index = 0;
100 size = read(fd, buf, BUFSIZ);
101 if (size == -1) {
102 clear();
103 refresh();
104 resetty();
105 endwin();
106 perror(filename);
107 }
108 if (!size)
109 return 0;
110 }
111 *input = buf[index++];
112 return 1;
113}
114
115filestruct *read_line(char *buf, filestruct * prev, int *line1ins)
116{
117 filestruct *fileptr;
118
119 fileptr = nmalloc(sizeof(filestruct));
Chris Allegretta88b09152001-05-17 11:35:43 +0000120 fileptr->data = charalloc(strlen(buf) + 2);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000121 strcpy(fileptr->data, buf);
122
123 if (*line1ins) {
124 /* Special case, insert with cursor on 1st line. */
125 fileptr->prev = NULL;
126 fileptr->next = fileage;
127 fileptr->lineno = 1;
128 *line1ins = 0;
129 /* If we're inserting into the first line of the file, then
130 we want to make sure that our edit buffer stays on the
131 first line (and that fileage stays up to date!) */
132 fileage = fileptr;
133 edittop = fileptr;
134 } else if (fileage == NULL) {
135 fileage = fileptr;
136 fileage->lineno = 1;
137 fileage->next = fileage->prev = NULL;
138 fileptr = filebot = fileage;
139 } else if (prev) {
140 fileptr->prev = prev;
141 fileptr->next = NULL;
142 fileptr->lineno = prev->lineno + 1;
143 prev->next = fileptr;
144 } else {
145 die(_("read_line: not on first line and prev is NULL"));
146 }
147
148 return fileptr;
149}
150
151
152int read_file(int fd, char *filename)
153{
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000154 long size, num_lines = 0, linetemp = 0;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000155 char input[2]; /* buffer */
156 char *buf;
157 long i = 0, bufx = 128;
158 filestruct *fileptr = current, *tmp = NULL;
159 int line1ins = 0;
160
Chris Allegretta88b09152001-05-17 11:35:43 +0000161 buf = charalloc(bufx);
Chris Allegretta8f6c0692000-07-19 01:16:18 +0000162 buf[0] = '\0';
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000163
164 if (fileptr != NULL && fileptr->prev != NULL) {
165 fileptr = fileptr->prev;
166 tmp = fileptr;
167 } else if (fileptr != NULL && fileptr->prev == NULL) {
168 tmp = fileage;
169 current = fileage;
170 line1ins = 1;
171 }
172 input[1] = 0;
173 /* Read the entire file into file struct */
174 while ((size = read_byte(fd, filename, input)) > 0) {
175 linetemp = 0;
176 if (input[0] == '\n') {
177 fileptr = read_line(buf, fileptr, &line1ins);
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000178 num_lines++;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000179 buf[0] = 0;
180 i = 0;
181 } else {
182 /* Now we allocate a bigger buffer 128 characters at a time.
183 If we allocate a lot of space for one line, we may indeed
184 have to use a buffer this big later on, so we don't
Chris Allegretta88520c92001-05-05 17:45:54 +0000185 decrease it at all. We do free it at the end, though. */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000186
187 if (i >= bufx - 1) {
188 buf = nrealloc(buf, bufx + 128);
189 bufx += 128;
190 }
191 buf[i] = input[0];
192 buf[i + 1] = 0;
193 i++;
194 }
195 totsize += size;
196 }
197
198 /* Did we not get a newline but still have stuff to do? */
199 if (buf[0]) {
200 fileptr = read_line(buf, fileptr, &line1ins);
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000201 num_lines++;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000202 buf[0] = 0;
203 }
204 /* Did we even GET a file? */
Chris Allegretta9956e532000-11-26 02:09:53 +0000205 if (totsize == 0 || fileptr == NULL) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000206 new_file();
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000207 statusbar(_("Read %d lines"), num_lines);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000208 return 1;
209 }
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000210
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000211 if (current != NULL) {
212 fileptr->next = current;
213 current->prev = fileptr;
214 renumber(current);
215 current_x = 0;
216 placewewant = 0;
217 } else if (fileptr->next == NULL) {
218 filebot = fileptr;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000219 new_magicline();
Chris Allegretta321590a2000-12-10 06:03:40 +0000220 totsize--;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000221
222 /* Update the edit buffer */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000223 load_file();
224 }
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000225 statusbar(_("Read %d lines"), num_lines);
226 totlines += num_lines;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000227
228 free(buf);
229 close(fd);
230
231 return 1;
232}
233
234/* Open the file (and decide if it exists) */
235int open_file(char *filename, int insert, int quiet)
236{
237 int fd;
238 struct stat fileinfo;
239
240 if (!strcmp(filename, "") || stat(filename, &fileinfo) == -1) {
241 if (insert) {
242 if (!quiet)
243 statusbar(_("\"%s\" not found"), filename);
244 return -1;
245 } else {
246 /* We have a new file */
247 statusbar(_("New File"));
248 new_file();
249 }
250 } else if ((fd = open(filename, O_RDONLY)) == -1) {
251 if (!quiet)
252 statusbar("%s: %s", strerror(errno), filename);
Chris Allegretta3a7c0be2000-12-18 01:09:07 +0000253 if (!insert)
254 new_file();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000255 return -1;
256 } else { /* File is A-OK */
Chris Allegretta7960dcf2000-12-13 15:01:29 +0000257 if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
258 S_ISBLK(fileinfo.st_mode)) {
259 if (S_ISDIR(fileinfo.st_mode))
260 statusbar(_("File \"%s\" is a directory"), filename);
261 else
262 /* Don't open character or block files. Sorry, /dev/sndstat! */
263 statusbar(_("File \"%s\" is a device file"), filename);
264
Chris Allegrettaf45c18d2000-09-16 05:25:06 +0000265 if (!insert)
266 new_file();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000267 return -1;
268 }
269 if (!quiet)
270 statusbar(_("Reading File"));
271 read_file(fd, filename);
272 }
273
274 return 1;
275}
276
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000277int do_insertfile(int loading_file)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000278{
279 int i;
Chris Allegretta25f4e582000-11-25 05:03:20 +0000280 char *realname = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000281
282 wrap_reset();
Chris Allegretta6fe61492001-05-21 12:56:25 +0000283
284#ifndef DISABLE_MOUSE
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000285 currshortcut = insertfile_list;
286 currslen = INSERTFILE_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000287#endif
288
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000289 i = statusq(1, insertfile_list, INSERTFILE_LIST_LEN, "",
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000290 _("File to insert [from ./] "));
291 if (i != -1) {
292
293#ifdef DEBUG
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000294 fprintf(stderr, _("filename is %s"), answer);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000295#endif
296
Rocco Corsi06aca1c2001-01-11 05:30:31 +0000297#ifndef DISABLE_TABCOMP
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000298 realname = real_dir_from_tilde(answer);
Chris Allegretta09a80842000-11-30 02:31:13 +0000299#else
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000300 realname = mallocstrcpy(realname, answer);
Chris Allegretta09a80842000-11-30 02:31:13 +0000301#endif
Chris Allegretta25f4e582000-11-25 05:03:20 +0000302
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000303#ifndef DISABLE_BROWSER
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000304 if (i == NANO_TOFILES_KEY) {
Chris Allegretta150469a2001-01-05 21:13:14 +0000305
306 char *tmp = do_browse_from(realname);
Chris Allegretta6fe61492001-05-21 12:56:25 +0000307#ifndef DISABLE_MOUSE
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000308 currshortcut = insertfile_list;
309 currslen = INSERTFILE_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000310#endif
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000311
Rocco Corsi06aca1c2001-01-11 05:30:31 +0000312#ifdef DISABLE_TABCOMP
Chris Allegretta544347c2001-01-05 14:31:52 +0000313 realname = NULL;
Chris Allegretta123e5e62001-01-04 22:05:47 +0000314#endif
315 if (tmp != NULL)
Chris Allegretta544347c2001-01-05 14:31:52 +0000316 realname = mallocstrcpy(realname, tmp);
Chris Allegretta123e5e62001-01-04 22:05:47 +0000317 else
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000318 return do_insertfile(loading_file);
319 }
320#endif
321
Chris Allegretta355fbe52001-07-14 19:32:47 +0000322#ifdef ENABLE_MULTIBUFFER
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000323 if (loading_file) {
324
325 /* update the current entry in the open_files structure; we
326 don't need to check for duplicate entries (the conditions
327 that could create them are taken care of elsewhere) */
328 add_open_file(1, 0);
329
330 free_filestruct(current);
331 new_file();
332 UNSET(MODIFIED);
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000333 }
334#endif
335
Chris Allegretta25f4e582000-11-25 05:03:20 +0000336 i = open_file(realname, 1, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000337
Chris Allegretta355fbe52001-07-14 19:32:47 +0000338#ifdef ENABLE_MULTIBUFFER
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000339 if (loading_file)
340 filename = mallocstrcpy(filename, realname);
341#endif
342
Chris Allegretta25f4e582000-11-25 05:03:20 +0000343 free(realname);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000344
345 dump_buffer(fileage);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000346
Chris Allegretta355fbe52001-07-14 19:32:47 +0000347#ifdef ENABLE_MULTIBUFFER
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000348 if (loading_file)
349 load_file();
350 else
351#endif
352
353 set_modified();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000354
355 /* Here we want to rebuild the edit window */
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000356 fix_editbot();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000357
Chris Allegretta355fbe52001-07-14 19:32:47 +0000358#ifdef ENABLE_MULTIBUFFER
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000359 /* If we've loaded another file, update the titlebar's contents */
360 if (loading_file) {
361 clearok(topwin, FALSE);
362 titlebar(NULL);
363
364 /* And re-init the shortcut list */
365 shortcut_init(0);
366 }
367#endif
368
Chris Allegretta88520c92001-05-05 17:45:54 +0000369 /* If we've gone off the bottom, recenter; otherwise, just redraw */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000370 if (current->lineno > editbot->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000371 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000372 else
373 edit_refresh();
374
375 UNSET(KEEP_CUTBUFFER);
376 display_main_list();
377 return i;
378 } else {
379 statusbar(_("Cancelled"));
380 UNSET(KEEP_CUTBUFFER);
381 display_main_list();
382 return 0;
383 }
384}
385
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000386int do_insertfile_void(void)
387{
388 int result = 0;
Chris Allegretta355fbe52001-07-14 19:32:47 +0000389#ifdef ENABLE_MULTIBUFFER
390 result = do_insertfile(ISSET(MULTIBUFFER));
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000391#else
392 result = do_insertfile(0);
393#endif
394
395 display_main_list();
396 return result;
397}
398
Chris Allegretta355fbe52001-07-14 19:32:47 +0000399#ifdef ENABLE_MULTIBUFFER
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000400/*
401 * Add/update an entry to the open_files filestruct. If update is
402 * zero, a new entry is created; otherwise, the current entry is updated.
403 * If dup_fix is zero, checking for and handling duplicate entries is not
404 * done; otherwise, it is. Return 0 on success, 1 on error, or 2 on
405 * finding a duplicate entry.
406 */
407int add_open_file(int update, int dup_fix)
408{
409 filestruct *tmp;
410
411 if (!current || !filename)
412 return 1;
413
414 /* first, if duplicate checking is allowed, do it */
415 if (dup_fix) {
416
417 /* if duplicates were found and handled, we're done */
418 if (open_file_dup_fix(update))
419 return 2;
420 }
421
422 /* if no entries, make the first one */
423 if (!open_files) {
424 open_files = make_new_node(NULL);
425
426 /* if open_files->file is NULL at the nrealloc() below, we get a
427 segfault */
428 open_files->file = open_files;
429 }
430
431 else if (!update) {
432
433 /* otherwise, if we're not updating, make a new entry for
434 open_files and splice it in after the current one */
435
436#ifdef DEBUG
437 fprintf(stderr, _("filename is %s"), open_files->data);
438#endif
439
440 tmp = make_new_node(NULL);
441 splice_node(open_files, tmp, open_files->next);
442 open_files = open_files->next;
443
444 /* if open_files->file is NULL at the nrealloc() below, we get a
445 segfault */
446 open_files->file = open_files;
447 }
448
449 /* save current filename */
450 open_files->data = mallocstrcpy(open_files->data, filename);
451
452 /* save the full path location */
453 open_files->file_path = get_full_path(open_files->data);
454
455 /* save current total number of lines */
456 open_files->file_totlines = totlines;
457
458 /* save current total size */
459 open_files->file_totsize = totsize;
460
461 /* save current x-coordinate position */
462 open_files->file_current_x = current_x;
463
464 /* save current y-coordinate position */
465 open_files->file_current_y = current_y;
466
467 /* save current place we want */
468 open_files->file_placewewant = placewewant;
469
470 /* save current line number */
471 open_files->lineno = current->lineno;
472
473 /* save current filestruct */
474 open_files->file = nrealloc(open_files->file, sizeof(filestruct));
475 while (current->prev)
476 current = current->prev;
477 open_files->file = copy_filestruct(current);
478 do_gotoline(open_files->lineno, 1);
479 placewewant = open_files->file_placewewant;
480 update_line(current, current_x);
481
482 /* save current modification status */
483 open_files->file_modified = ISSET(MODIFIED);
484
485#ifdef DEBUG
486 fprintf(stderr, _("filename is %s"), open_files->data);
487#endif
488
489 return 0;
490}
491
492/*
493 * Update only the filename and full path stored in the current entry.
494 * Return 0 on success or 1 on error.
495 */
496int open_file_change_name(void)
497{
498 if (!open_files || !filename)
499 return 1;
500
501 /* save current filename */
502 open_files->data = mallocstrcpy(open_files->data, filename);
503
504 /* save the full path location */
505 open_files->file_path = get_full_path(open_files->data);
506
507 return 0;
508}
509
510/*
511 * Read the current entry in the open_files structure and set up the
512 * currently open file using that entry's information. Return 0 on
513 * success or 1 on error.
514 */
515int load_open_file(void)
516{
517 if (!open_files)
518 return 1;
519
520 /* set up the filename, the file buffer, the total number of lines in
521 the file, and the total file size */
522 filename = mallocstrcpy(filename, open_files->data);
523 fileage = copy_filestruct(open_files->file);
524 current = fileage;
525 totlines = open_files->file_totlines;
526 totsize = open_files->file_totsize;
527
528 /* since do_gotoline() resets the x-coordinate but not the
529 y-coordinate, set all coordinates up this way */
530 current_y = open_files->file_current_y;
531 do_gotoline(open_files->lineno, 1);
532 current_x = open_files->file_current_x;
533 placewewant = open_files->file_placewewant;
534 update_line(current, current_x);
535
536 /* set up modification status and update the titlebar */
537 if (open_files->file_modified)
538 SET(MODIFIED);
539 else
540 UNSET(MODIFIED);
541 clearok(topwin, FALSE);
542 titlebar(NULL);
543
544 /* if we're constantly displaying the cursor position, update it */
545 if (ISSET(CONSTUPDATE))
546 do_cursorpos();
547
548 /* now we're done */
549 return 0;
550}
551
552/*
553 * Search the open_files structure for an entry with the same value for
554 * the file_path member as the current entry (i. e. a duplicate entry).
555 * If one is found, return a pointer to it; otherwise, return NULL.
556 *
557 * Note: This should only be called inside open_file_dup_fix().
558 */
559filestruct *open_file_dup_search(void)
560{
561 filestruct *tmp;
562 char *path;
563
564 if (!open_files || !filename)
565 return NULL;
566
567 tmp = open_files;
568 path = get_full_path(filename);
569
570 /* if there's only one entry, handle it */
571 if (!tmp->prev && !tmp->next) {
572 if (!strcmp(tmp->file_path, path))
573 return tmp;
574 }
575
576 /* otherwise, go to the beginning */
577 while (tmp->prev)
578 tmp = tmp->prev;
579
580 /* and search the entries one by one */
581 while (tmp) {
582
583 if (!strcmp(tmp->file_path, path)) {
584
585 /* if it's not the current entry, we've found a duplicate */
586 if (tmp != open_files)
587 return tmp;
588 }
589
590 /* go to the next entry */
591 tmp = tmp->next;
592
593 }
594
595 return NULL;
596}
597
598/*
599 * Search for duplicate entries in the open_files structure using
600 * open_file_dup_search(), and, if one is found, handle it properly.
601 * Return 0 if no duplicates were found, and 1 otherwise.
602 */
603int open_file_dup_fix(int update)
604{
605 filestruct *tmp = open_file_dup_search();
606
607 if (!tmp)
608 return 0;
609
610 /* if there's only one entry, handle it */
611 if (!tmp->prev && !tmp->next)
612 return 1;
613
614 /* otherwise, if we're not updating, the user's trying to load a
615 duplicate; switch to the original instead */
616 if (!update) {
617 open_files = tmp;
618 return 1;
619 }
620
621 /* if we are updating, the filename's been changed via a save; it's
622 thus more recent than the original, so remove the original */
623 else {
624 unlink_node(tmp);
625 free_filestruct(tmp->file);
626 free(tmp->file_path);
627 delete_node(tmp);
628 }
629 return 0;
630}
631
632/*
633 * Open the previous entry in the open_files structure. If closing_file
634 * is zero, update the current entry before switching from it.
635 * Otherwise, we are about to close that entry, so don't bother doing so.
636 * Return 0 on success and 1 on error.
637 */
638int open_prevfile(int closing_file)
639{
640 if (!open_files)
641 return 1;
642
643 /* if we're not about to close the current entry, update it before
644 doing anything; since we're only switching, we don't need to check
645 for duplicate entries */
646 if (!closing_file)
647 add_open_file(1, 0);
648
649 if (!open_files->prev && !open_files->next) {
650
651 /* only one file open */
652 if (!closing_file)
653 statusbar(_("No more open files"));
654 return 1;
655 }
656
657 if (open_files->prev) {
658 open_files = open_files->prev;
659
660#ifdef DEBUG
661 fprintf(stderr, _("filename is %s"), open_files->data);
662#endif
663
664 }
665
666 else if (open_files->next) {
667
668 /* if we're at the beginning, wrap around to the end */
669 while (open_files->next)
670 open_files = open_files->next;
671
672#ifdef DEBUG
673 fprintf(stderr, _("filename is %s"), open_files->data);
674#endif
675
676 }
677
678 load_open_file();
679
680#ifdef DEBUG
681 dump_buffer(current);
682#endif
683
684 return 0;
685}
686
687/*
688 * Open the next entry in the open_files structure. If closing_file is
689 * zero, update the current entry before switching from it. Otherwise, we
690 * are about to close that entry, so don't bother doing so. Return 0 on
691 * success and 1 on error.
692 */
693int open_nextfile(int closing_file)
694{
695 if (!open_files)
696 return 1;
697
698 /* if we're not about to close the current entry, update it before
699 doing anything; since we're only switching, we don't need to check
700 for duplicate entries */
701 if (!closing_file)
702 add_open_file(1, 0);
703
704 if (!open_files->prev && !open_files->next) {
705
706 /* only one file open */
707 if (!closing_file)
708 statusbar(_("No more open files"));
709 return 1;
710 }
711
712 if (open_files->next) {
713 open_files = open_files->next;
714
715#ifdef DEBUG
716 fprintf(stderr, _("filename is %s"), open_files->data);
717#endif
718
719 }
720 else if (open_files->prev) {
721
722 /* if we're at the end, wrap around to the beginning */
723 while (open_files->prev) {
724 open_files = open_files->prev;
725
726#ifdef DEBUG
727 fprintf(stderr, _("filename is %s"), open_files->data);
728#endif
729
730 }
731 }
732
733 load_open_file();
734
735#ifdef DEBUG
736 dump_buffer(current);
737#endif
738
739 return 0;
740}
741
742/*
743 * Delete an entry from the open_files filestruct. After deletion of an
Chris Allegrettae6421972001-07-18 01:03:36 +0000744 * entry, the next or previous entry is opened, whichever is found first.
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000745 * Return 0 on success or 1 on error.
746 */
747int close_open_file(void)
748{
749 filestruct *tmp;
750
751 if (!open_files)
752 return 1;
753
754 tmp = open_files;
Chris Allegrettae6421972001-07-18 01:03:36 +0000755 if (open_nextfile(1)) {
756 if (open_prevfile(1))
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000757 return 1;
758 }
759
760 unlink_node(tmp);
761 free_filestruct(tmp->file);
762 free(tmp->file_path);
763 delete_node(tmp);
764
765 shortcut_init(0);
766 display_main_list();
767 return 0;
768}
769
770/*
771 * When passed "[relative path][filename]" in origpath, return "[full
772 * path][filename]" on success, or NULL on error.
773 */
774char *get_full_path(const char *origpath)
775{
776 char *newpath = NULL, *last_slash, *d_here, *d_there, *d_there_file;
777 int last_slash_index;
778
779 /* first, get the current directory */
780
781#ifdef PATH_MAX
782 d_here = getcwd(NULL, PATH_MAX + 1);
783#else
784 d_here = getcwd(NULL, 0);
785#endif
786
787 if (d_here) {
788
789 align(&d_here);
790
791 /* get the filename (with path included) and save it in both
792 d_there and d_there_file */
793 d_there = charalloc(strlen(origpath) + 1);
794 d_there_file = charalloc(strlen(origpath) + 1);
795 strcpy(d_there, origpath);
796 strcpy(d_there_file, origpath);
797
798 /* search for the last slash in d_there */
799 last_slash = strrchr(d_there, '/');
800
801 /* if we didn't find one, copy d_here into d_there; all data is
802 then set up */
803 if (!last_slash) {
804 d_there = nrealloc(d_there, strlen(d_here) + 1);
805 strcpy(d_there, d_here);
806 }
807
808 else {
809
810 /* otherwise, remove all non-path elements from d_there */
811 last_slash_index = strlen(d_there) - strlen(last_slash);
812 null_at(d_there, last_slash_index);
813
814 /* and remove all non-file elements from d_there_file */
815 last_slash++;
816 d_there_file = nrealloc(d_there_file, strlen(last_slash) + 1);
817 strcpy(d_there_file, last_slash);
818
819 /* now go to the path specified in d_there */
820 if (chdir(d_there) != -1) {
821
822 /* get the full pathname, and save it back in d_there */
823
824 free(d_there);
825
826#ifdef PATH_MAX
827 d_there = getcwd(NULL, PATH_MAX + 1);
828#else
829 d_there = getcwd(NULL, 0);
830#endif
831
832 align(&d_there);
833 }
834
835 /* finally, go back to where we were before, d_here (no error
836 checking is done on this chdir(), because we can do
837 nothing if it fails) */
838 chdir(d_here);
839 }
840
841 /* all data is set up; fill in newpath */
842
843 /* newpath = d_there + "/" + d_there_file */
844 newpath = charalloc(strlen(d_there) + strlen(d_there_file) + 2);
845 strcpy(newpath, d_there);
846 strcat(newpath, "/");
847 strcat(newpath, d_there_file);
848
849 /* finally, clean up */
850 free(d_there_file);
851 free(d_there);
852 free(d_here);
853 }
854
855 return newpath;
856}
857#endif
858
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000859/*
860 * Write a file out. If tmp is nonzero, we set the umask to 0600,
Chris Allegretta88520c92001-05-05 17:45:54 +0000861 * we don't set the global variable filename to its name, and don't
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000862 * print out how many lines we wrote on the statusbar.
863 *
Chris Allegretta49805172001-03-28 02:14:28 +0000864 * tmp means we are writing a tmp file in a secure fashion. We use
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000865 * it when spell checking or dumping the file on an error.
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000866 *
867 * append means, not surprisingly, whether we are appending instead
868 * of overwriting.
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +0000869 *
870 * nonamechange means don't change the current filename, it is ignored
871 * if tmp == 1.
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000872 */
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +0000873int write_file(char *name, int tmp, int append, int nonamechange)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000874{
875 long size, lineswritten = 0;
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000876 static char *buf = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000877 filestruct *fileptr;
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000878 int fd, mask = 0, realexists, anyexists;
Chris Allegretta7960dcf2000-12-13 15:01:29 +0000879 struct stat st, lst;
Chris Allegretta0f5dfef2000-11-24 14:02:57 +0000880 static char *realname = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000881
882 if (!strcmp(name, "")) {
883 statusbar(_("Cancelled"));
884 return -1;
885 }
Chris Allegrettaf4b96012001-01-03 07:11:47 +0000886 titlebar(NULL);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000887 fileptr = fileage;
Chris Allegretta0f5dfef2000-11-24 14:02:57 +0000888
889 if (realname != NULL)
890 free(realname);
891
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000892 if (buf != NULL)
893 free(buf);
894
Rocco Corsi06aca1c2001-01-11 05:30:31 +0000895#ifndef DISABLE_TABCOMP
Chris Allegrettabe77c612000-11-24 14:00:16 +0000896 realname = real_dir_from_tilde(name);
897#else
898 realname = mallocstrcpy(realname, name);
899#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000900
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000901 /* Save the state of file at the end of the symlink (if there is one) */
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000902 realexists = stat(realname, &st);
903
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000904 /* Stat the link itself for the check... */
905 anyexists = lstat(realname, &lst);
Chris Allegrettaacb62342000-07-21 22:42:46 +0000906
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000907 /* New case: if the file exists, just give up */
908 if (tmp && anyexists != -1)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000909 return -1;
Chris Allegrettab5bb24c2000-12-06 00:57:54 +0000910 /* NOTE: If you change this statement, you MUST CHANGE the if
Chris Allegretta544d9b02000-12-11 02:47:13 +0000911 statement below (that says:
912 if (realexists == -1 || tmp || (!ISSET(FOLLOW_SYMLINKS) &&
913 S_ISLNK(lst.st_mode))) {
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000914 to reflect whether or not to link/unlink/rename the file */
915 else if (ISSET(FOLLOW_SYMLINKS) || !S_ISLNK(lst.st_mode) || tmp) {
Chris Allegretta33084392000-12-09 22:50:38 +0000916 /* Use O_EXCL if tmp == 1. This is now copied from joe, because
Chris Allegrettaf5977772000-12-09 23:58:41 +0000917 wiggy says so *shrug*. */
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000918 if (append)
919 fd = open(realname, O_WRONLY | O_APPEND, (S_IRUSR|S_IWUSR));
920 else if (tmp)
Chris Allegrettaf5977772000-12-09 23:58:41 +0000921 fd = open(realname, O_WRONLY | O_CREAT | O_EXCL, (S_IRUSR|S_IWUSR));
922 else
923 fd = open(realname, O_WRONLY | O_CREAT | O_TRUNC, (S_IRUSR|S_IWUSR));
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000924
925 /* First, just give up if we couldn't even open the file */
Chris Allegretta59828492000-12-04 03:31:39 +0000926 if (fd == -1) {
Chris Allegretta20c131c2000-12-04 04:20:09 +0000927 if (!tmp && ISSET(TEMP_OPT)) {
Chris Allegrettaa299b032000-07-14 02:44:02 +0000928 UNSET(TEMP_OPT);
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000929 return do_writeout(filename, 1, 0);
Chris Allegrettaa299b032000-07-14 02:44:02 +0000930 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000931 statusbar(_("Could not open file for writing: %s"),
932 strerror(errno));
933 return -1;
934 }
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000935
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000936 }
937 /* Don't follow symlink. Create new file. */
938 else {
Chris Allegretta88b09152001-05-17 11:35:43 +0000939 buf = charalloc(strlen(realname) + 8);
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000940 strncpy(buf, realname, strlen(realname)+1);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000941 strcat(buf, ".XXXXXX");
942 if ((fd = mkstemp(buf)) == -1) {
Chris Allegrettaa299b032000-07-14 02:44:02 +0000943 if (ISSET(TEMP_OPT)) {
944 UNSET(TEMP_OPT);
Chris Allegrettacc197ef2001-05-29 04:21:44 +0000945 return do_writeout(filename, 1, 0);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000946 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000947 statusbar(_("Could not open file for writing: %s"),
948 strerror(errno));
949 return -1;
950 }
951 }
952
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000953 dump_buffer(fileage);
954 while (fileptr != NULL && fileptr->next != NULL) {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000955 /* Next line is so we discount the "magic line" */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000956 if (filebot == fileptr && fileptr->data[0] == '\0')
957 break;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000958
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000959 size = write(fd, fileptr->data, strlen(fileptr->data));
960 if (size == -1) {
961 statusbar(_("Could not open file for writing: %s"),
962 strerror(errno));
963 return -1;
964 } else {
965#ifdef DEBUG
966 fprintf(stderr, _("Wrote >%s\n"), fileptr->data);
967#endif
968 }
969 write(fd, "\n", 1);
970
971 fileptr = fileptr->next;
972 lineswritten++;
973 }
974
975 if (fileptr != NULL) {
976 size = write(fd, fileptr->data, strlen(fileptr->data));
977 if (size == -1) {
978 statusbar(_("Could not open file for writing: %s"),
979 strerror(errno));
980 return -1;
981 } else if (size > 0) {
982 size = write(fd, "\n", 1);
Chris Allegretta1a8b2962001-06-30 18:41:08 +0000983 lineswritten++;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000984 if (size == -1) {
985 statusbar(_("Could not open file for writing: %s"),
986 strerror(errno));
987 return -1;
988 }
989 }
990 }
991
992
993 if (close(fd) == -1) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000994 statusbar(_("Could not close %s: %s"), realname, strerror(errno));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000995 unlink(buf);
996 return -1;
997 }
998
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000999 if (realexists == -1 || tmp ||
1000 (!ISSET(FOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001001
Chris Allegretta88520c92001-05-05 17:45:54 +00001002 /* Use default umask as file permissions if file is a new file. */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001003 mask = umask(0);
1004 umask(mask);
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001005
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001006 if (tmp) /* We don't want anyone reading our temporary file! */
1007 mask = 0600;
1008 else
1009 mask = 0666 & ~mask;
1010 } else
Chris Allegrettada13f0b2000-12-06 05:59:31 +00001011 /* Use permissions from file we are overwriting. */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001012 mask = st.st_mode;
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001013
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001014 if (!tmp && (!ISSET(FOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001015 if (unlink(realname) == -1) {
1016 if (errno != ENOENT) {
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +00001017 statusbar(_("Could not open %s for writing: %s"),
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001018 realname, strerror(errno));
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +00001019 unlink(buf);
1020 return -1;
1021 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001022 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001023 if (link(buf, realname) != -1)
1024 unlink(buf);
1025 else if (errno != EPERM) {
1026 statusbar(_("Could not open %s for writing: %s"),
1027 name, strerror(errno));
1028 unlink(buf);
1029 return -1;
1030 } else if (rename(buf, realname) == -1) { /* Try a rename?? */
1031 statusbar(_("Could not open %s for writing: %s"),
1032 realname, strerror(errno));
1033 unlink(buf);
1034 return -1;
1035 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001036 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001037 if (chmod(realname, mask) == -1)
1038 statusbar(_("Could not set permissions %o on %s: %s"),
1039 mask, realname, strerror(errno));
1040
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001041 if (!tmp) {
Chris Allegretta0241d192001-06-05 23:45:54 +00001042 if (!nonamechange)
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001043 filename = mallocstrcpy(filename, realname);
1044
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001045 statusbar(_("Wrote %d lines"), lineswritten);
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001046 UNSET(MODIFIED);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001047 titlebar(NULL);
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001048 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001049 return 1;
1050}
1051
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001052int do_writeout(char *path, int exiting, int append)
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001053{
1054 int i = 0;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001055
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00001056#ifdef NANO_EXTRA
1057 static int did_cred = 0;
1058#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001059
Chris Allegretta6fe61492001-05-21 12:56:25 +00001060#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001061 currshortcut = writefile_list;
1062 currslen = WRITEFILE_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +00001063#endif
1064
Chris Allegrettae1ebaf32001-01-07 05:50:36 +00001065 answer = mallocstrcpy(answer, path);
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001066
Chris Allegretta962c3c92000-07-24 21:52:17 +00001067 if ((exiting) && (ISSET(TEMP_OPT))) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001068 if (filename[0]) {
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001069 i = write_file(answer, 0, 0, 0);
Chris Allegretta962c3c92000-07-24 21:52:17 +00001070 display_main_list();
1071 return i;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001072 } else {
Chris Allegretta461b2a92000-07-24 22:05:18 +00001073 UNSET(TEMP_OPT);
1074 do_exit();
1075
1076 /* They cancelled, abort quit */
1077 return -1;
Chris Allegretta962c3c92000-07-24 21:52:17 +00001078 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001079 }
1080
1081 while (1) {
Chris Allegretta500b5e32001-06-21 23:58:47 +00001082#ifndef NANO_SMALL
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001083 if (ISSET(MARK_ISSET) && !exiting)
Chris Allegrettad21195f2001-06-05 22:57:43 +00001084 i = statusq(1, writefile_list, WRITEFILE_LIST_LEN, "",
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001085 _("%s Selection to File"), append ? _("Append") : _("Write"));
1086 else
Chris Allegretta500b5e32001-06-21 23:58:47 +00001087#endif
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001088 i = statusq(1, writefile_list, WRITEFILE_LIST_LEN, answer,
1089 _("File Name to %s"), append ? _("Append") : _("Write"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001090
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001091 if (i != -1) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001092
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001093#ifndef DISABLE_BROWSER
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001094 if (i == NANO_TOFILES_KEY) {
Chris Allegretta150469a2001-01-05 21:13:14 +00001095
1096 char *tmp = do_browse_from(answer);
Chris Allegretta6fe61492001-05-21 12:56:25 +00001097
1098#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001099 currshortcut = writefile_list;
1100 currslen = WRITEFILE_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +00001101#endif
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001102
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001103 if (tmp != NULL) {
Chris Allegretta544347c2001-01-05 14:31:52 +00001104 answer = mallocstrcpy(answer, tmp);
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001105 } else
1106 return do_writeout(answer, exiting, append);
1107 } else
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001108#endif
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001109 if (i == NANO_APPEND_KEY)
1110 return(do_writeout(answer, exiting, 1 - append));
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001111
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001112#ifdef DEBUG
1113 fprintf(stderr, _("filename is %s"), answer);
1114#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00001115
1116#ifdef NANO_EXTRA
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001117 if (exiting && !ISSET(TEMP_OPT) && !strcasecmp(answer, "zzy")
1118 && !did_cred) {
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00001119 do_credits();
1120 did_cred = 1;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001121 return -1;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00001122 }
1123#endif
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001124 if (!append && strcmp(answer, filename)) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001125 struct stat st;
1126 if (!stat(answer, &st)) {
1127 i = do_yesno(0, 0, _("File exists, OVERWRITE ?"));
1128
1129 if (!i || (i == -1))
1130 continue;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001131 }
1132 }
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001133#ifndef NANO_SMALL
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001134
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001135 /* Here's where we allow the selected text to be written to
1136 a separate file. */
1137 if (ISSET(MARK_ISSET) && !exiting) {
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001138 filestruct *fileagebak = fileage;
1139 filestruct *filebotbak = filebot;
1140 filestruct *cutback = cutbuffer;
1141 int oldmod = 0;
Chris Allegretta500b5e32001-06-21 23:58:47 +00001142 cutbuffer = NULL;
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001143
1144 /* Okay, since write_file changes the filename, back it up */
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001145 if (ISSET(MODIFIED))
1146 oldmod = 1;
1147
1148 /* Now, non-destructively add the marked text to the
1149 cutbuffer, and write the file out using the cutbuffer ;) */
Chris Allegretta500b5e32001-06-21 23:58:47 +00001150 if (current->lineno <= mark_beginbuf->lineno)
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001151 cut_marked_segment(current, current_x, mark_beginbuf,
1152 mark_beginx, 0);
1153 else
1154 cut_marked_segment(mark_beginbuf, mark_beginx, current,
1155 current_x, 0);
1156
1157 fileage = cutbuffer;
1158 for (filebot = cutbuffer; filebot->next != NULL;
1159 filebot = filebot->next)
1160 ;
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001161 i = write_file(answer, 0, append, 1);
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001162
1163 /* Now restore everything */
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001164 fileage = fileagebak;
1165 filebot = filebotbak;
1166 cutbuffer = cutback;
1167 if (oldmod)
1168 set_modified();
1169 } else
1170#endif
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001171 i = write_file(answer, 0, append, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001172
Chris Allegretta355fbe52001-07-14 19:32:47 +00001173#ifdef ENABLE_MULTIBUFFER
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001174 /* if we're not about to exit, update the current entry in
1175 the open_files structure */
1176 if (!exiting) {
1177
1178 /* first, if the filename was changed during the save,
1179 update the filename and full path stored in the
1180 current entry, and then update the current entry,
1181 checking for duplicate entries */
Chris Allegrettae6421972001-07-18 01:03:36 +00001182 if (strcmp(open_files->data, filename)) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001183 open_file_change_name();
1184 add_open_file(1, 1);
1185 }
1186 else {
1187
1188 /* otherwise, just update the current entry without
1189 checking for duplicate entries */
1190 add_open_file(1, 0);
1191 }
1192 }
1193#endif
1194
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001195 display_main_list();
1196 return i;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001197 } else {
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001198 statusbar(_("Cancelled"));
1199 display_main_list();
1200 return 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001201 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001202 }
1203}
1204
1205int do_writeout_void(void)
1206{
Chris Allegrettacc197ef2001-05-29 04:21:44 +00001207 return do_writeout(filename, 0, 0);
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001208}
Chris Allegretta04d848e2000-11-05 17:54:41 +00001209
Rocco Corsi06aca1c2001-01-11 05:30:31 +00001210#ifndef DISABLE_TABCOMP
Chris Allegrettabe77c612000-11-24 14:00:16 +00001211
1212/* Return a malloc()ed string containing the actual directory, used
1213 * to convert ~user and ~/ notation...
1214 */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001215char *real_dir_from_tilde(char *buf)
Chris Allegrettabe77c612000-11-24 14:00:16 +00001216{
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001217 char *dirtmp = NULL, *find_user = NULL;
1218 int i = 1;
Chris Allegrettaee733e62001-01-22 22:17:08 +00001219 struct passwd *userdata;
Chris Allegrettabe77c612000-11-24 14:00:16 +00001220
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001221 /* set a default value for dirtmp, in the case user home dir not found */
1222 dirtmp = mallocstrcpy(dirtmp, buf);
1223
Chris Allegrettabe77c612000-11-24 14:00:16 +00001224 if (buf[0] == '~') {
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001225 if (buf[1] == 0 || buf[1] == '/') {
Chris Allegrettabe77c612000-11-24 14:00:16 +00001226 if (getenv("HOME") != NULL) {
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001227
1228 free(dirtmp);
Chris Allegretta88b09152001-05-17 11:35:43 +00001229 dirtmp = charalloc(strlen(buf) + 2 + strlen(getenv("HOME")));
Chris Allegrettabe77c612000-11-24 14:00:16 +00001230
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001231 sprintf(dirtmp, "%s%s", getenv("HOME"), &buf[1]);
Chris Allegrettabf692612001-01-08 16:59:19 +00001232
Chris Allegrettabe77c612000-11-24 14:00:16 +00001233 }
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001234 }
1235 else {
Chris Allegrettabe77c612000-11-24 14:00:16 +00001236
Chris Allegretta88520c92001-05-05 17:45:54 +00001237 /* Figure how how much of the str we need to compare */
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001238 for (i = 1; buf[i] != '/' && buf[i] != 0; i++)
1239 ;
1240
1241 find_user = mallocstrcpy(find_user, &buf[1]);
1242 find_user[i - 1] = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +00001243
Chris Allegrettaee733e62001-01-22 22:17:08 +00001244 for (userdata = getpwent(); userdata != NULL &&
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001245 strcmp(userdata->pw_name, find_user);
Chris Allegrettaee733e62001-01-22 22:17:08 +00001246 userdata = getpwent());
Chris Allegretta04fec912000-11-25 04:43:43 +00001247
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001248 free(find_user);
Chris Allegretta04fec912000-11-25 04:43:43 +00001249
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001250 if (userdata != NULL) { /* User found */
Chris Allegretta04fec912000-11-25 04:43:43 +00001251
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001252 free(dirtmp);
Chris Allegretta88b09152001-05-17 11:35:43 +00001253 dirtmp = charalloc(strlen(buf) + 2 + strlen(userdata->pw_dir));
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001254 sprintf(dirtmp, "%s%s", userdata->pw_dir, &buf[i]);
1255
1256 }
1257
Chris Allegrettaee733e62001-01-22 22:17:08 +00001258 endpwent();
Chris Allegrettabe77c612000-11-24 14:00:16 +00001259 }
Chris Allegrettae5e4d492001-01-23 03:09:15 +00001260 }
Chris Allegrettabe77c612000-11-24 14:00:16 +00001261
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001262 return dirtmp;
Chris Allegrettabe77c612000-11-24 14:00:16 +00001263}
1264
1265/* Tack a slash onto the string we're completing if it's a directory */
Chris Allegretta04fec912000-11-25 04:43:43 +00001266int append_slash_if_dir(char *buf, int *lastWasTab, int *place)
Chris Allegrettabe77c612000-11-24 14:00:16 +00001267{
1268 char *dirptr;
1269 struct stat fileinfo;
Chris Allegretta04fec912000-11-25 04:43:43 +00001270 int ret = 0;
Chris Allegrettabe77c612000-11-24 14:00:16 +00001271
1272 dirptr = real_dir_from_tilde(buf);
1273
1274 if (stat(dirptr, &fileinfo) == -1)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001275 ret = 0;
Chris Allegrettabe77c612000-11-24 14:00:16 +00001276 else if (S_ISDIR(fileinfo.st_mode)) {
1277 strncat(buf, "/", 1);
1278 *place += 1;
1279 /* now we start over again with # of tabs so far */
1280 *lastWasTab = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +00001281 ret = 1;
Chris Allegrettabe77c612000-11-24 14:00:16 +00001282 }
1283
1284 if (dirptr != buf)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001285 free(dirptr);
Chris Allegretta04fec912000-11-25 04:43:43 +00001286
1287 return ret;
Chris Allegrettabe77c612000-11-24 14:00:16 +00001288}
Chris Allegretta04d848e2000-11-05 17:54:41 +00001289
1290/*
1291 * These functions (username_tab_completion, cwd_tab_completion, and
1292 * input_tab were taken from busybox 0.46 (cmdedit.c). Here is the notice
1293 * from that file:
1294 *
1295 * Termios command line History and Editting, originally
1296 * intended for NetBSD sh (ash)
1297 * Copyright (c) 1999
1298 * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
1299 * Etc: Dave Cinege <dcinege@psychosis.com>
1300 * Majorly adjusted/re-written for busybox:
1301 * Erik Andersen <andersee@debian.org>
1302 *
1303 * You may use this code as you wish, so long as the original author(s)
1304 * are attributed in any redistributions of the source code.
1305 * This code is 'as is' with no warranty.
1306 * This code may safely be consumed by a BSD or GPL license.
1307 */
1308
1309char **username_tab_completion(char *buf, int *num_matches)
1310{
Chris Allegretta2c2c5f22001-01-23 03:27:31 +00001311 char **matches = (char **) NULL;
Chris Allegretta8d9b11a2001-01-19 04:17:24 +00001312 char *matchline = NULL;
Chris Allegretta2c2c5f22001-01-23 03:27:31 +00001313 struct passwd *userdata;
Chris Allegrettabe77c612000-11-24 14:00:16 +00001314
Chris Allegretta8d9b11a2001-01-19 04:17:24 +00001315 *num_matches = 0;
Rocco Corsi8b6cccc2001-01-02 06:21:07 +00001316 matches = nmalloc(BUFSIZ * sizeof(char *));
Chris Allegretta8d9b11a2001-01-19 04:17:24 +00001317
Chris Allegrettabe77c612000-11-24 14:00:16 +00001318 strcat(buf, "*");
Chris Allegretta8d9b11a2001-01-19 04:17:24 +00001319
Chris Allegretta2c2c5f22001-01-23 03:27:31 +00001320 while ((userdata = getpwent()) != NULL) {
Chris Allegrettabe77c612000-11-24 14:00:16 +00001321
Chris Allegretta2c2c5f22001-01-23 03:27:31 +00001322 if (check_wildcard_match(userdata->pw_name, &buf[1]) == TRUE) {
Chris Allegrettabe77c612000-11-24 14:00:16 +00001323
Chris Allegrettabe77c612000-11-24 14:00:16 +00001324 /* Cool, found a match. Add it to the list
1325 * This makes a lot more sense to me (Chris) this way...
1326 */
Chris Allegretta8d9b11a2001-01-19 04:17:24 +00001327
Chris Allegretta88b09152001-05-17 11:35:43 +00001328 matchline = charalloc(strlen(userdata->pw_name) + 2);
Chris Allegretta2c2c5f22001-01-23 03:27:31 +00001329 sprintf(matchline, "~%s", userdata->pw_name);
1330 matches[*num_matches] = matchline;
1331 ++*num_matches;
Chris Allegrettabe77c612000-11-24 14:00:16 +00001332
Chris Allegretta2c2c5f22001-01-23 03:27:31 +00001333 /* If there's no more room, bail out */
1334 if (*num_matches == BUFSIZ)
1335 break;
Chris Allegrettabe77c612000-11-24 14:00:16 +00001336 }
Chris Allegretta2c2c5f22001-01-23 03:27:31 +00001337 }
1338 endpwent();
Chris Allegretta8d9b11a2001-01-19 04:17:24 +00001339
Chris Allegretta04d848e2000-11-05 17:54:41 +00001340 return (matches);
1341}
1342
1343/* This was originally called exe_n_cwd_tab_completion, but we're not
1344 worried about executables, only filenames :> */
1345
1346char **cwd_tab_completion(char *buf, int *num_matches)
1347{
Chris Allegrettabe77c612000-11-24 14:00:16 +00001348 char *dirName, *dirtmp = NULL, *tmp = NULL, *tmp2 = NULL;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001349 char **matches = (char **) NULL;
1350 DIR *dir;
1351 struct dirent *next;
1352
Rocco Corsi8b6cccc2001-01-02 06:21:07 +00001353 matches = nmalloc(BUFSIZ * sizeof(char *));
Chris Allegretta04d848e2000-11-05 17:54:41 +00001354
1355 /* Stick a wildcard onto the buf, for later use */
1356 strcat(buf, "*");
1357
Chris Allegretta2c975222000-11-15 01:25:42 +00001358 /* Okie, if there's a / in the buffer, strip out the directory part */
Chris Allegretta04d848e2000-11-05 17:54:41 +00001359 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegretta88b09152001-05-17 11:35:43 +00001360 dirName = charalloc(strlen(buf) + 1);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001361 tmp = buf + strlen(buf);
1362 while (*tmp != '/' && tmp != buf)
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001363 tmp--;
Chris Allegretta442f2c52000-11-14 17:46:06 +00001364
Chris Allegretta04d848e2000-11-05 17:54:41 +00001365 tmp++;
1366
Chris Allegretta442f2c52000-11-14 17:46:06 +00001367 strncpy(dirName, buf, tmp - buf + 1);
1368 dirName[tmp - buf] = 0;
Chris Allegretta442f2c52000-11-14 17:46:06 +00001369
Chris Allegretta04d848e2000-11-05 17:54:41 +00001370 } else {
Chris Allegretta90d30742001-04-03 01:02:38 +00001371
1372#ifdef PATH_MAX
1373 if ((dirName = getcwd(NULL, PATH_MAX+1)) == NULL)
1374#else
Chris Allegretta88520c92001-05-05 17:45:54 +00001375 /* The better, but apparently segfault-causing way */
Chris Allegretta04d848e2000-11-05 17:54:41 +00001376 if ((dirName = getcwd(NULL, 0)) == NULL)
Chris Allegretta90d30742001-04-03 01:02:38 +00001377#endif /* PATH_MAX */
Chris Allegretta04d848e2000-11-05 17:54:41 +00001378 return matches;
1379 else
1380 tmp = buf;
1381 }
1382
1383#ifdef DEBUG
1384 fprintf(stderr, "\nDir = %s\n", dirName);
1385 fprintf(stderr, "\nbuf = %s\n", buf);
1386 fprintf(stderr, "\ntmp = %s\n", tmp);
1387#endif
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001388
Chris Allegrettabe77c612000-11-24 14:00:16 +00001389 dirtmp = real_dir_from_tilde(dirName);
1390 free(dirName);
1391 dirName = dirtmp;
1392
1393#ifdef DEBUG
1394 fprintf(stderr, "\nDir = %s\n", dirName);
1395 fprintf(stderr, "\nbuf = %s\n", buf);
1396 fprintf(stderr, "\ntmp = %s\n", tmp);
1397#endif
1398
1399
Chris Allegretta04d848e2000-11-05 17:54:41 +00001400 dir = opendir(dirName);
1401 if (!dir) {
1402 /* Don't print an error, just shut up and return */
1403 *num_matches = 0;
1404 beep();
1405 return (matches);
1406 }
1407 while ((next = readdir(dir)) != NULL) {
1408
Chris Allegretta04d848e2000-11-05 17:54:41 +00001409#ifdef DEBUG
Chris Allegretta2c975222000-11-15 01:25:42 +00001410 fprintf(stderr, "Comparing \'%s\'\n", next->d_name);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001411#endif
1412 /* See if this matches */
1413 if (check_wildcard_match(next->d_name, tmp) == TRUE) {
Chris Allegretta7d97ce72000-11-06 04:04:15 +00001414
1415 /* Cool, found a match. Add it to the list
1416 * This makes a lot more sense to me (Chris) this way...
1417 */
1418 tmp2 = NULL;
Chris Allegretta88b09152001-05-17 11:35:43 +00001419 tmp2 = charalloc(strlen(next->d_name) + 1);
Chris Allegretta7d97ce72000-11-06 04:04:15 +00001420 strcpy(tmp2, next->d_name);
1421 matches[*num_matches] = tmp2;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001422 ++*num_matches;
Chris Allegretta2c975222000-11-15 01:25:42 +00001423
1424 /* If there's no more room, bail out */
1425 if (*num_matches == BUFSIZ)
1426 break;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001427 }
1428 }
1429
1430 return (matches);
1431}
1432
Chris Allegretta442f2c52000-11-14 17:46:06 +00001433/* This function now has an arg which refers to how much the
Chris Allegretta04d848e2000-11-05 17:54:41 +00001434 * statusbar (place) should be advanced, i.e. the new cursor pos.
1435 */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001436char *input_tab(char *buf, int place, int *lastWasTab, int *newplace)
Chris Allegretta04d848e2000-11-05 17:54:41 +00001437{
1438 /* Do TAB completion */
Chris Allegrettaec58a992000-11-05 21:54:23 +00001439 static int num_matches = 0, match_matches = 0;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001440 static char **matches = (char **) NULL;
Chris Allegretta442f2c52000-11-14 17:46:06 +00001441 int pos = place, i = 0, col = 0, editline = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +00001442 int longestname = 0, is_dir = 0;
Chris Allegretta3b0d1442000-11-05 21:56:54 +00001443 char *foo;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001444
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001445 if (*lastWasTab == FALSE) {
Chris Allegretta442f2c52000-11-14 17:46:06 +00001446 char *tmp, *copyto, *matchBuf;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001447
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001448 *lastWasTab = 1;
1449
Chris Allegretta04d848e2000-11-05 17:54:41 +00001450 /* Make a local copy of the string -- up to the position of the
1451 cursor */
Chris Allegrettaa35ec042001-01-15 02:26:12 +00001452 matchBuf = (char *) nmalloc((strlen(buf) + 2) * sizeof(char));
Chris Allegretta40587092001-01-16 04:45:38 +00001453 memset(matchBuf, '\0', (strlen(buf) + 2));
Chris Allegrettae118acc2000-11-06 05:40:03 +00001454
Chris Allegretta04d848e2000-11-05 17:54:41 +00001455 strncpy(matchBuf, buf, place);
1456 tmp = matchBuf;
1457
1458 /* skip any leading white space */
Chris Allegretta63a89d32000-11-18 03:05:50 +00001459 while (*tmp && isspace((int) *tmp))
Chris Allegretta04d848e2000-11-05 17:54:41 +00001460 ++tmp;
1461
1462 /* Free up any memory already allocated */
1463 if (matches != NULL) {
Chris Allegretta442f2c52000-11-14 17:46:06 +00001464 for (i = i; i < num_matches; i++)
1465 free(matches[i]);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001466 free(matches);
1467 matches = (char **) NULL;
Chris Allegretta7d97ce72000-11-06 04:04:15 +00001468 num_matches = 0;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001469 }
1470
1471 /* If the word starts with `~' and there is no slash in the word,
1472 * then try completing this word as a username. */
1473
Chris Allegrettabe77c612000-11-24 14:00:16 +00001474 /* FIXME -- this check is broken! */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +00001475 if (*tmp == '~' && !strchr(tmp, '/'))
1476 matches = username_tab_completion(tmp, &num_matches);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001477
1478 /* Try to match everything in the current working directory that
1479 * matches. */
1480 if (!matches)
1481 matches = cwd_tab_completion(tmp, &num_matches);
1482
1483 /* Don't leak memory */
1484 free(matchBuf);
1485
Chris Allegretta442f2c52000-11-14 17:46:06 +00001486#ifdef DEBUG
1487 fprintf(stderr, "%d matches found...\n", num_matches);
1488#endif
Chris Allegretta04d848e2000-11-05 17:54:41 +00001489 /* Did we find exactly one match? */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001490 switch (num_matches) {
Chris Allegrettae118acc2000-11-06 05:40:03 +00001491 case 0:
Chris Allegretta24342432000-11-06 05:41:20 +00001492 blank_edit();
Chris Allegretta2c975222000-11-15 01:25:42 +00001493 wrefresh(edit);
Chris Allegrettae118acc2000-11-06 05:40:03 +00001494 break;
1495 case 1:
Chris Allegretta442f2c52000-11-14 17:46:06 +00001496
1497 buf = nrealloc(buf, strlen(buf) + strlen(matches[0]) + 1);
1498
1499 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001500 for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
1501 tmp--);
Chris Allegretta442f2c52000-11-14 17:46:06 +00001502 tmp++;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001503 } else
Chris Allegretta442f2c52000-11-14 17:46:06 +00001504 tmp = buf;
1505
Chris Allegretta04fec912000-11-25 04:43:43 +00001506 if (!strcmp(tmp, matches[0]))
1507 is_dir = append_slash_if_dir(buf, lastWasTab, newplace);
1508
1509 if (is_dir)
1510 break;
Chris Allegretta442f2c52000-11-14 17:46:06 +00001511
1512 copyto = tmp;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001513 for (pos = 0; *tmp == matches[0][pos] &&
1514 pos <= strlen(matches[0]); pos++)
Chris Allegretta442f2c52000-11-14 17:46:06 +00001515 tmp++;
1516
Chris Allegretta2c975222000-11-15 01:25:42 +00001517 /* write out the matched name */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001518 strncpy(copyto, matches[0], strlen(matches[0]) + 1);
Chris Allegretta442f2c52000-11-14 17:46:06 +00001519 *newplace += strlen(matches[0]) - pos;
1520
Chris Allegrettabe77c612000-11-24 14:00:16 +00001521 /* Is it a directory? */
1522 append_slash_if_dir(buf, lastWasTab, newplace);
1523
Chris Allegrettae118acc2000-11-06 05:40:03 +00001524 break;
1525 default:
Chris Allegretta88520c92001-05-05 17:45:54 +00001526 /* Check to see if all matches share a beginning, and, if so,
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001527 tack it onto buf and then beep */
Chris Allegrettaec58a992000-11-05 21:54:23 +00001528
Chris Allegretta442f2c52000-11-14 17:46:06 +00001529 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001530 for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
1531 tmp--);
Chris Allegretta442f2c52000-11-14 17:46:06 +00001532 tmp++;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001533 } else
Chris Allegretta442f2c52000-11-14 17:46:06 +00001534 tmp = buf;
1535
1536 for (pos = 0; *tmp == matches[0][pos] && *tmp != 0 &&
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001537 pos <= strlen(matches[0]); pos++)
Chris Allegretta442f2c52000-11-14 17:46:06 +00001538 tmp++;
1539
Chris Allegrettaec58a992000-11-05 21:54:23 +00001540 while (1) {
1541 match_matches = 0;
1542
1543 for (i = 0; i < num_matches; i++) {
1544 if (matches[i][pos] == 0)
1545 break;
1546 else if (matches[i][pos] == matches[0][pos])
1547 match_matches++;
1548 }
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001549 if (match_matches == num_matches &&
1550 (i == num_matches || matches[i] != 0)) {
Chris Allegrettaec58a992000-11-05 21:54:23 +00001551 /* All the matches have the same character at pos+1,
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001552 so paste it into buf... */
Chris Allegretta75864952000-11-05 22:48:35 +00001553 buf = nrealloc(buf, strlen(buf) + 2);
Chris Allegretta442f2c52000-11-14 17:46:06 +00001554 strncat(buf, matches[0] + pos, 1);
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001555 *newplace += 1;
Chris Allegrettaec58a992000-11-05 21:54:23 +00001556 pos++;
Chris Allegretta75864952000-11-05 22:48:35 +00001557 } else {
Chris Allegrettaec58a992000-11-05 21:54:23 +00001558 beep();
1559 break;
1560 }
1561 }
Chris Allegrettae118acc2000-11-06 05:40:03 +00001562 break;
Chris Allegrettaec58a992000-11-05 21:54:23 +00001563 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001564 } else {
1565 /* Ok -- the last char was a TAB. Since they
1566 * just hit TAB again, print a list of all the
1567 * available choices... */
1568 if (matches && num_matches > 0) {
Chris Allegretta04d848e2000-11-05 17:54:41 +00001569
1570 /* Blank the edit window, and print the matches out there */
1571 blank_edit();
1572 wmove(edit, 0, 0);
1573
Chris Allegrettaec58a992000-11-05 21:54:23 +00001574 editline = 0;
Chris Allegretta2c975222000-11-15 01:25:42 +00001575
Chris Allegrettaec58a992000-11-05 21:54:23 +00001576 /* Figure out the length of the longest filename */
1577 for (i = 0; i < num_matches; i++)
1578 if (strlen(matches[i]) > longestname)
1579 longestname = strlen(matches[i]);
1580
1581 if (longestname > COLS - 1)
1582 longestname = COLS - 1;
1583
Chris Allegretta88b09152001-05-17 11:35:43 +00001584 foo = charalloc(longestname + 5);
Chris Allegretta3b0d1442000-11-05 21:56:54 +00001585
Chris Allegretta04d848e2000-11-05 17:54:41 +00001586 /* Print the list of matches */
1587 for (i = 0, col = 0; i < num_matches; i++) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001588
Chris Allegrettaec58a992000-11-05 21:54:23 +00001589 /* make each filename shown be the same length as the longest
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001590 filename, with two spaces at the end */
Chris Allegrettaec58a992000-11-05 21:54:23 +00001591 snprintf(foo, longestname + 1, matches[i]);
1592 while (strlen(foo) < longestname)
1593 strcat(foo, " ");
1594
1595 strcat(foo, " ");
1596
Chris Allegretta442f2c52000-11-14 17:46:06 +00001597 /* Disable el cursor */
1598 curs_set(0);
Chris Allegretta75864952000-11-05 22:48:35 +00001599 /* now, put the match on the screen */
1600 waddnstr(edit, foo, strlen(foo));
1601 col += strlen(foo);
1602
1603 /* And if the next match isn't going to fit on the
1604 line, move to the next one */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001605 if (col > (COLS - longestname) && matches[i + 1] != NULL) {
Chris Allegrettaec58a992000-11-05 21:54:23 +00001606 editline++;
1607 wmove(edit, editline, 0);
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001608 if (editline == editwinrows - 1) {
1609 waddstr(edit, _("(more)"));
1610 break;
1611 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001612 col = 0;
1613 }
1614 }
Chris Allegretta3b0d1442000-11-05 21:56:54 +00001615 free(foo);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001616 wrefresh(edit);
Chris Allegretta24dd8d62000-11-06 05:45:48 +00001617 } else
1618 beep();
Chris Allegretta04d848e2000-11-05 17:54:41 +00001619
1620 }
1621
1622 edit_refresh();
Chris Allegretta442f2c52000-11-14 17:46:06 +00001623 curs_set(1);
1624 return buf;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001625}
Chris Allegrettabe77c612000-11-24 14:00:16 +00001626#endif
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001627
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001628#ifndef DISABLE_BROWSER
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001629
1630/* Return the stat of the file pointed to by path */
1631struct stat filestat(const char *path) {
1632 struct stat st;
1633
Chris Allegretta0876dc92001-03-28 13:04:08 +00001634 stat(path, &st);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001635 return st;
1636}
1637
1638/* Our sort routine for file listings - sort directories before
1639 * files, and then alphabetically
1640 */
1641int diralphasort(const void *va, const void *vb) {
1642 struct stat file1info, file2info;
1643 char *a = *(char **)va, *b = *(char **)vb;
Chris Allegretta90d30742001-04-03 01:02:38 +00001644 int aisdir, bisdir;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001645
Chris Allegretta90d30742001-04-03 01:02:38 +00001646 aisdir = (stat(a, &file1info) != -1) && S_ISDIR(file1info.st_mode);
1647 bisdir = (stat(b, &file2info) != -1) && S_ISDIR(file2info.st_mode);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001648
Chris Allegretta90d30742001-04-03 01:02:38 +00001649 if (aisdir && !bisdir) return -1;
1650 if (!aisdir && bisdir) return 1;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001651
Chris Allegretta90d30742001-04-03 01:02:38 +00001652#ifdef HAVE_STRCASECMP
1653 return(strcasecmp(a,b));
1654#else
1655 return(strcmp(a,b));
1656#endif
1657
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001658}
1659
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001660
1661/* Initialize the browser code, including the list of files in *path */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001662char **browser_init(char *path, int *longest, int *numents)
1663{
1664 DIR *dir;
1665 struct dirent *next;
1666 char **filelist = (char **) NULL;
1667 int i = 0;
1668
1669 dir = opendir(path);
1670 if (!dir)
1671 return NULL;
1672
1673 *numents = 0;
1674 while ((next = readdir(dir)) != NULL) {
1675 if (!strcmp(next->d_name, "."))
1676 continue;
1677 (*numents)++;
1678 if (strlen(next->d_name) > *longest)
1679 *longest = strlen(next->d_name);
1680 }
1681 rewinddir(dir);
1682 *longest += 10;
1683
1684 filelist = nmalloc(*numents * sizeof (char *));
1685
1686 while ((next = readdir(dir)) != NULL) {
1687 if (!strcmp(next->d_name, "."))
1688 continue;
Chris Allegretta88b09152001-05-17 11:35:43 +00001689 filelist[i] = charalloc(strlen(next->d_name) + strlen(path) + 2);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001690
1691 if (!strcmp(path, "/"))
1692 snprintf(filelist[i], strlen(next->d_name) + strlen(path) + 1,
1693 "%s%s", path, next->d_name);
1694 else
1695 snprintf(filelist[i], strlen(next->d_name) + strlen(path) + 2,
1696 "%s/%s", path, next->d_name);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001697 i++;
1698 }
1699
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001700 if (*longest > COLS - 1)
1701 *longest = COLS - 1;
1702
1703 return filelist;
1704}
1705
Chris Allegretta88520c92001-05-05 17:45:54 +00001706/* Free our malloc()ed memory */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001707void free_charptrarray(char **array, int len)
1708{
1709 int i;
1710
1711 for (i = 0; i < len - 1; i++)
1712 free(array[i]);
1713 free(array);
1714}
1715
Chris Allegretta88520c92001-05-05 17:45:54 +00001716/* only print the last part of a path; isn't there a shell
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001717 command for this? */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001718char *tail(char *foo)
1719{
1720 char *tmp = NULL;
1721
1722 tmp = foo + strlen(foo);
1723 while (*tmp != '/' && tmp != foo)
1724 tmp--;
1725
1726 tmp++;
1727
1728 return tmp;
1729}
1730
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001731/* Strip one dir from the end of a string */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001732void striponedir(char *foo)
1733{
1734 char *tmp = NULL;
1735
1736 /* Don't strip the root dir */
1737 if (!strcmp(foo, "/"))
1738 return;
1739
1740 tmp = foo + strlen(foo);
1741 if (*tmp == '/')
1742 tmp--;
1743
1744 while (*tmp != '/' && tmp != foo)
1745 tmp--;
1746
1747 if (tmp != foo)
1748 *tmp = 0;
1749 else
1750 *(tmp+1) = 0;
1751
1752 return;
1753}
1754
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001755/* Our browser function. inpath is the path to start browsing from */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001756char *do_browser(char *inpath)
1757{
1758 struct stat st;
1759 char *foo, *retval = NULL;
1760 static char *path = NULL;
1761 int numents = 0, i = 0, j = 0, kbinput = 0, longest = 0, abort = 0;
1762 int col = 0, selected = 0, editline = 0, width = 0, filecols = 0;
Chris Allegrettac08f50d2001-01-06 18:12:43 +00001763 int lineno = 0, kb;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001764 char **filelist = (char **) NULL;
Chris Allegretta051fc6e2001-05-05 23:17:36 +00001765#ifndef DISABLE_MOUSE
1766#ifdef NCURSES_MOUSE_VERSION
1767 MEVENT mevent;
1768#endif
1769#endif
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001770
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001771 /* If path isn't the same as inpath, we are being passed a new
1772 dir as an arg. We free it here so it will be copied from
1773 inpath below */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001774 if (path != NULL && strcmp(path, inpath)) {
1775 free(path);
1776 path = NULL;
1777 }
1778
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001779 /* if path doesn't exist, make it so */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001780 if (path == NULL)
1781 path = mallocstrcpy(path, inpath);
1782
1783 filelist = browser_init(path, &longest, &numents);
Chris Allegretta88b09152001-05-17 11:35:43 +00001784 foo = charalloc(longest + 8);
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001785
Chris Allegretta88520c92001-05-05 17:45:54 +00001786 /* Sort the list by directory first, then alphabetically */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001787 qsort(filelist, numents, sizeof(char *), diralphasort);
1788
Chris Allegrettac08f50d2001-01-06 18:12:43 +00001789 kb = keypad_on(edit, 1);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001790 titlebar(path);
1791 bottombars(browser_list, BROWSER_LIST_LEN);
1792 curs_set(0);
1793 wmove(edit, 0, 0);
1794 i = 0;
1795 width = 0;
1796 filecols = 0;
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001797
1798 /* Loop invariant: Microsoft sucks. */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001799 do {
Rocco Corsi12f294c2001-04-14 06:50:24 +00001800 DIR *test_dir;
1801
1802 blank_statusbar_refresh();
1803
Chris Allegretta6fe61492001-05-21 12:56:25 +00001804#ifndef DISABLE_MOUSE
Chris Allegrettab10283c2001-05-07 12:08:37 +00001805 currshortcut = browser_list;
1806 currslen = BROWSER_LIST_LEN;
Chris Allegretta6fe61492001-05-21 12:56:25 +00001807#endif
1808
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001809 editline = 0;
1810 col = 0;
Chris Allegrettab0f52822001-01-04 05:20:23 +00001811
Chris Allegretta88520c92001-05-05 17:45:54 +00001812 /* Compute line number we're on now, so we don't divide by zero later */
Chris Allegrettab0f52822001-01-04 05:20:23 +00001813 if (width == 0)
1814 lineno = selected;
1815 else
1816 lineno = selected / width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001817
1818 switch (kbinput) {
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001819
Chris Allegretta051fc6e2001-05-05 23:17:36 +00001820#ifndef DISABLE_MOUSE
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001821#ifdef NCURSES_MOUSE_VERSION
1822 case KEY_MOUSE:
Chris Allegretta051fc6e2001-05-05 23:17:36 +00001823 if (getmouse(&mevent) == ERR)
1824 return retval;
1825
1826 /* If they clicked in the edit window, they probably clicked
1827 on a file */
1828 if (wenclose(edit, mevent.y, mevent.x)) {
1829 int selectedbackup = selected;
1830
1831 mevent.y -= 2;
1832
1833 /* If we're on line 0, don't toy with finding out what
1834 page we're on */
1835 if (lineno / editwinrows == 0)
1836 selected = mevent.y * width + mevent.x / longest;
1837 else
1838 selected = (lineno / editwinrows) * editwinrows * width
1839 + mevent.y * width + mevent.x / longest;
1840
1841 /* If we're off the screen, reset to the last item.
1842 If we clicked where we did last time, select this name! */
Chris Allegrettaf3fde7c2001-05-06 03:02:21 +00001843 if (selected > numents - 1)
Chris Allegretta051fc6e2001-05-05 23:17:36 +00001844 selected = numents - 1;
1845 else if (selectedbackup == selected) {
1846 ungetch('s'); /* Unget the 'select' key */
1847 break;
1848 }
1849 } else /* Must be clicking a shortcut */
1850 do_mouse();
1851
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001852 break;
1853#endif
1854#endif
Chris Allegrettaa2c02e92001-07-02 01:31:44 +00001855 case NANO_UP_KEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001856 case KEY_UP:
1857 case 'u':
1858 if (selected - width >= 0)
1859 selected -= width;
1860 break;
Chris Allegrettaa2c02e92001-07-02 01:31:44 +00001861 case NANO_BACK_KEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001862 case KEY_LEFT:
Chris Allegrettaa2c02e92001-07-02 01:31:44 +00001863 case NANO_BACKSPACE_KEY:
1864 case 127:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001865 case 'l':
1866 if (selected > 0)
1867 selected--;
1868 break;
1869 case KEY_DOWN:
Chris Allegrettaa2c02e92001-07-02 01:31:44 +00001870 case NANO_DOWN_KEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001871 case 'd':
1872 if (selected + width <= numents - 1)
1873 selected += width;
1874 break;
1875 case KEY_RIGHT:
Chris Allegrettaa2c02e92001-07-02 01:31:44 +00001876 case NANO_FORWARD_KEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001877 case 'r':
1878 if (selected < numents - 1)
1879 selected++;
1880 break;
1881 case NANO_PREVPAGE_KEY:
Chris Allegretta6e827412001-01-04 04:41:08 +00001882 case NANO_PREVPAGE_FKEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001883 case KEY_PPAGE:
Chris Allegretta8eac3b52001-01-08 21:14:04 +00001884 case '-':
Chris Allegrettab0f52822001-01-04 05:20:23 +00001885
1886 if (lineno % editwinrows == 0) {
Chris Allegretta425a2662001-01-03 15:09:27 +00001887 if (selected - (editwinrows * width) >= 0)
1888 selected -= editwinrows * width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001889 else
1890 selected = 0;
1891 }
1892 else if (selected - (editwinrows +
Chris Allegrettab0f52822001-01-04 05:20:23 +00001893 lineno % editwinrows) * width >= 0)
1894
1895 selected -= (editwinrows + lineno % editwinrows) * width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001896 else
1897 selected = 0;
1898 break;
1899 case NANO_NEXTPAGE_KEY:
Chris Allegretta6e827412001-01-04 04:41:08 +00001900 case NANO_NEXTPAGE_FKEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001901 case KEY_NPAGE:
Chris Allegretta8eac3b52001-01-08 21:14:04 +00001902 case ' ':
Chris Allegrettab0f52822001-01-04 05:20:23 +00001903 if (lineno % editwinrows == 0) {
Chris Allegretta425a2662001-01-03 15:09:27 +00001904 if (selected + (editwinrows * width) <= numents - 1)
1905 selected += editwinrows * width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001906 else
1907 selected = numents - 1;
1908 }
1909 else if (selected + (editwinrows -
Chris Allegrettab0f52822001-01-04 05:20:23 +00001910 lineno % editwinrows) * width <= numents - 1)
1911 selected += (editwinrows - lineno % editwinrows) * width;
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001912 else
1913 selected = numents - 1;
1914 break;
1915 case KEY_ENTER:
Chris Allegrettaa2c02e92001-07-02 01:31:44 +00001916 case NANO_ENTER_KEY:
Chris Allegrettaba8edea2001-01-04 05:22:46 +00001917 case 's': /* More Pico compatibility */
1918 case 'S':
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001919
1920 /* You can't cd up from / */
Rocco Corsi12f294c2001-04-14 06:50:24 +00001921 if (!strcmp(filelist[selected], "/..") && !strcmp(path, "/")) {
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001922 statusbar(_("Can't move up a directory"));
Rocco Corsi12f294c2001-04-14 06:50:24 +00001923 break;
1924 }
1925
1926 path = mallocstrcpy(path, filelist[selected]);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001927
1928 st = filestat(path);
1929 if (S_ISDIR(st.st_mode)) {
Rocco Corsi12f294c2001-04-14 06:50:24 +00001930 if ((test_dir = opendir(path)) == NULL) {
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001931 /* We can't open this dir for some reason. Complain */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001932 statusbar(_("Can't open \"%s\": %s"), path, strerror(errno));
Rocco Corsi12f294c2001-04-14 06:50:24 +00001933 striponedir(path);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001934 align(&path);
1935 break;
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001936 }
Rocco Corsi12f294c2001-04-14 06:50:24 +00001937 closedir(test_dir);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001938
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001939 if (!strcmp("..", tail(path))) {
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001940 /* They want to go up a level, so strip off .. and the
1941 current dir */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001942 striponedir(path);
1943 striponedir(path);
1944 align(&path);
1945 }
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00001946
1947 /* Start over again with the new path value */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001948 return do_browser(path);
1949 } else {
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001950 retval = path;
1951 abort = 1;
1952 }
1953 break;
Rocco Corsi12f294c2001-04-14 06:50:24 +00001954 /* Goto a specific directory */
1955 case 'g': /* Pico compatibility */
1956 case 'G':
1957 case NANO_GOTO_KEY:
1958
1959 curs_set(1);
1960 j = statusq(0, gotodir_list, GOTODIR_LIST_LEN, "", _("Goto Directory"));
1961 bottombars(browser_list, BROWSER_LIST_LEN);
1962 curs_set(0);
1963
1964 if (j < 0) {
1965 statusbar(_("Goto Cancelled"));
1966 break;
1967 }
1968
1969 if (answer[0] != '/') {
1970 char *saveanswer = NULL;
1971
1972 saveanswer = mallocstrcpy(saveanswer, answer);
1973 answer = realloc(answer, strlen(path) + strlen(saveanswer) + 2);
1974 sprintf(answer, "%s/%s", path, saveanswer);
1975 free(saveanswer);
1976 }
1977
1978 if ((test_dir = opendir(answer)) == NULL) {
1979 /* We can't open this dir for some reason. Complain */
1980 statusbar(_("Can't open \"%s\": %s"), answer, strerror(errno));
1981 break;
1982 }
1983 closedir(test_dir);
1984
1985 /* Start over again with the new path value */
1986 path = mallocstrcpy(path, answer);
1987 return do_browser(path);
1988
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001989 /* Stuff we want to abort the browser */
1990 case 'q':
1991 case 'Q':
1992 case 'e': /* Pico compatibility, yeech */
1993 case 'E':
Chris Allegrettaa2c02e92001-07-02 01:31:44 +00001994 case NANO_CANCEL_KEY:
Chris Allegretta6e827412001-01-04 04:41:08 +00001995 case NANO_EXIT_FKEY:
Chris Allegrettaf4b96012001-01-03 07:11:47 +00001996 abort = 1;
1997 break;
1998 }
1999 if (abort)
2000 break;
2001
Rocco Corsi12f294c2001-04-14 06:50:24 +00002002 blank_edit();
2003
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002004 if (width)
2005 i = width * editwinrows * ((selected / width) / editwinrows);
2006 else
2007 i = 0;
2008
2009 wmove(edit, 0, 0);
2010 for (j = i; j < numents && editline <= editwinrows - 1; j++) {
2011 filecols++;
2012
2013 strncpy(foo, tail(filelist[j]), strlen(tail(filelist[j])) + 1);
2014 while (strlen(foo) < longest)
2015 strcat(foo, " ");
2016 col += strlen(foo);
2017
2018 /* Put file info in the string also */
Chris Allegretta88520c92001-05-05 17:45:54 +00002019 /* We use lstat here to detect links; then, if we find a
2020 symlink, we examine it via stat() to see if it is a
Chris Allegretta0876dc92001-03-28 13:04:08 +00002021 directory or just a file symlink */
2022 lstat(filelist[j], &st);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002023 if (S_ISDIR(st.st_mode))
2024 strcpy(foo + longest - 5, "(dir)");
2025 else {
Chris Allegretta0876dc92001-03-28 13:04:08 +00002026 if (S_ISLNK(st.st_mode)) {
2027 /* Aha! It's a symlink! Now, is it a dir? If so,
2028 mark it as such */
2029 st = filestat(filelist[j]);
2030 if (S_ISDIR(st.st_mode))
2031 strcpy(foo + longest - 5, "(dir)");
2032 else
2033 strcpy(foo + longest - 2, "--");
Chris Allegretta90d30742001-04-03 01:02:38 +00002034 } else if (st.st_size < (1 << 10)) /* less than 1 K */
2035 sprintf(foo + longest - 7, "%4d B",
Chris Allegrettad4615622001-05-23 21:54:47 +00002036 (int) st.st_size);
Chris Allegretta90d30742001-04-03 01:02:38 +00002037 else if (st.st_size >= (1 << 30)) /* at least 1 gig */
2038 sprintf(foo + longest - 7, "%4d GB",
2039 (int) st.st_size >> 30);
2040 else if (st.st_size >= (1 << 20)) /* at least 1 meg */
2041 sprintf(foo + longest - 7, "%4d MB",
2042 (int) st.st_size >> 20);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002043 else /* Its more than 1 k and less than a meg */
Chris Allegretta90d30742001-04-03 01:02:38 +00002044 sprintf(foo + longest - 7, "%4d KB",
2045 (int) st.st_size >> 10);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002046 }
2047
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00002048 /* Hilight the currently selected file/dir */
Chris Allegretta8ce24132001-04-30 11:28:46 +00002049 if (j == selected) {
2050#ifdef ENABLE_COLOR
2051 color_on(edit, COLOR_STATUSBAR);
2052#else
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002053 wattron(edit, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002054
2055#endif
2056 }
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002057 waddnstr(edit, foo, strlen(foo));
Chris Allegretta8ce24132001-04-30 11:28:46 +00002058 if (j == selected) {
2059#ifdef ENABLE_COLOR
2060 color_off(edit, COLOR_STATUSBAR);
2061#else
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002062 wattroff(edit, A_REVERSE);
Chris Allegretta8ce24132001-04-30 11:28:46 +00002063#endif
2064 }
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002065
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00002066 /* And add some space between the cols */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002067 waddstr(edit, " ");
2068 col += 2;
2069
2070 /* And if the next entry isn't going to fit on the
2071 line, move to the next one */
2072 if (col > (COLS - longest)) {
2073 editline++;
2074 wmove(edit, editline, 0);
2075 col = 0;
2076 if (width == 0)
2077 width = filecols;
2078 }
2079 }
2080 wrefresh(edit);
2081 } while ((kbinput = wgetch(edit)) != NANO_EXIT_KEY);
2082 curs_set(1);
2083 blank_edit();
2084 titlebar(NULL);
2085 edit_refresh();
Chris Allegrettac08f50d2001-01-06 18:12:43 +00002086 kb = keypad_on(edit, kb);
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002087
Chris Allegretta0e9d3c62001-01-04 04:59:17 +00002088 /* cleanup */
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002089 free_charptrarray(filelist, numents);
2090 free(foo);
2091 return retval;
2092}
Chris Allegretta150469a2001-01-05 21:13:14 +00002093
Chris Allegretta88520c92001-05-05 17:45:54 +00002094/* Browser front end, checks to see if inpath has a dir in it and, if so,
Chris Allegretta150469a2001-01-05 21:13:14 +00002095 starts do_browser from there, else from the current dir */
2096char *do_browse_from(char *inpath)
2097{
2098 struct stat st;
2099 char *tmp = NULL;
2100
2101 tmp = mallocstrcpy(tmp, inpath);
2102
Chris Allegretta90d30742001-04-03 01:02:38 +00002103
Chris Allegretta88520c92001-05-05 17:45:54 +00002104 /* If there's no / in the string, we may as well start from . */
Chris Allegretta90d30742001-04-03 01:02:38 +00002105 if (tmp == NULL || *tmp == '\0' || !strstr(tmp, "/")) {
2106#ifdef PATH_MAX
2107 char *from = getcwd(NULL, PATH_MAX+1);
2108#else
Chris Allegretta60c65422001-04-03 14:26:35 +00002109 char *from = getcwd(NULL, 0);
Chris Allegretta90d30742001-04-03 01:02:38 +00002110#endif /* PATH_MAX */
2111 return do_browser(from ? from : "./");
2112 }
Chris Allegretta150469a2001-01-05 21:13:14 +00002113
2114 /* If the string is a directory, pass do_browser that */
2115 st = filestat(tmp);
2116 if (S_ISDIR(st.st_mode))
2117 return do_browser(tmp);
2118
2119 /* Okay, there's a dir in there, but not at the end of the string...
2120 try stripping it off */
2121 striponedir(tmp);
2122 align(&tmp);
2123 return do_browser(tmp);
2124
2125}
2126
2127
2128
Chris Allegrettaf4b96012001-01-03 07:11:47 +00002129#endif
2130