blob: 2b1c41cd2ade9572d50423de5f6ff73f864f5e1d [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
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h>
25#include <unistd.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <errno.h>
Chris Allegretta04d848e2000-11-05 17:54:41 +000030#include <ctype.h>
31#include <dirent.h>
Chris Allegrettabceb1b22000-06-19 04:22:15 +000032
33#include "config.h"
34#include "proto.h"
35#include "nano.h"
Chris Allegretta4da1fc62000-06-21 03:00:43 +000036
Chris Allegrettabceb1b22000-06-19 04:22:15 +000037#ifndef NANO_SMALL
38#include <libintl.h>
39#define _(string) gettext(string)
40#else
41#define _(string) (string)
42#endif
43
44/* Load file into edit buffer - takes data from file struct */
45void load_file(void)
46{
47 current = fileage;
48 wmove(edit, current_y, current_x);
49}
50
51/* What happens when there is no file to open? aiee! */
52void new_file(void)
53{
54 fileage = nmalloc(sizeof(filestruct));
55 fileage->data = nmalloc(1);
56 strcpy(fileage->data, "");
57 fileage->prev = NULL;
58 fileage->next = NULL;
59 fileage->lineno = 1;
60 filebot = fileage;
61 edittop = fileage;
62 editbot = fileage;
63 current = fileage;
64 totlines = 1;
65 UNSET(VIEW_MODE);
66}
67
68
69int read_byte(int fd, char *filename, char *input)
70{
71 static char buf[BUFSIZ];
72 static int index = 0;
73 static int size = 0;
74
75 if (index == size) {
76 index = 0;
77 size = read(fd, buf, BUFSIZ);
78 if (size == -1) {
79 clear();
80 refresh();
81 resetty();
82 endwin();
83 perror(filename);
84 }
85 if (!size)
86 return 0;
87 }
88 *input = buf[index++];
89 return 1;
90}
91
92filestruct *read_line(char *buf, filestruct * prev, int *line1ins)
93{
94 filestruct *fileptr;
95
96 fileptr = nmalloc(sizeof(filestruct));
97 fileptr->data = nmalloc(strlen(buf) + 2);
98 strcpy(fileptr->data, buf);
99
100 if (*line1ins) {
101 /* Special case, insert with cursor on 1st line. */
102 fileptr->prev = NULL;
103 fileptr->next = fileage;
104 fileptr->lineno = 1;
105 *line1ins = 0;
106 /* If we're inserting into the first line of the file, then
107 we want to make sure that our edit buffer stays on the
108 first line (and that fileage stays up to date!) */
109 fileage = fileptr;
110 edittop = fileptr;
111 } else if (fileage == NULL) {
112 fileage = fileptr;
113 fileage->lineno = 1;
114 fileage->next = fileage->prev = NULL;
115 fileptr = filebot = fileage;
116 } else if (prev) {
117 fileptr->prev = prev;
118 fileptr->next = NULL;
119 fileptr->lineno = prev->lineno + 1;
120 prev->next = fileptr;
121 } else {
122 die(_("read_line: not on first line and prev is NULL"));
123 }
124
125 return fileptr;
126}
127
128
129int read_file(int fd, char *filename)
130{
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000131 long size, num_lines = 0, linetemp = 0;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000132 char input[2]; /* buffer */
133 char *buf;
134 long i = 0, bufx = 128;
135 filestruct *fileptr = current, *tmp = NULL;
136 int line1ins = 0;
137
138 buf = nmalloc(bufx);
Chris Allegretta8f6c0692000-07-19 01:16:18 +0000139 buf[0] = '\0';
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000140
141 if (fileptr != NULL && fileptr->prev != NULL) {
142 fileptr = fileptr->prev;
143 tmp = fileptr;
144 } else if (fileptr != NULL && fileptr->prev == NULL) {
145 tmp = fileage;
146 current = fileage;
147 line1ins = 1;
148 }
149 input[1] = 0;
150 /* Read the entire file into file struct */
151 while ((size = read_byte(fd, filename, input)) > 0) {
152 linetemp = 0;
153 if (input[0] == '\n') {
154 fileptr = read_line(buf, fileptr, &line1ins);
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000155 num_lines++;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000156 buf[0] = 0;
157 i = 0;
158 } else {
159 /* Now we allocate a bigger buffer 128 characters at a time.
160 If we allocate a lot of space for one line, we may indeed
161 have to use a buffer this big later on, so we don't
162 decrease it at all. We do free it at the end though. */
163
164 if (i >= bufx - 1) {
165 buf = nrealloc(buf, bufx + 128);
166 bufx += 128;
167 }
168 buf[i] = input[0];
169 buf[i + 1] = 0;
170 i++;
171 }
172 totsize += size;
173 }
174
175 /* Did we not get a newline but still have stuff to do? */
176 if (buf[0]) {
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 }
181 /* Did we even GET a file? */
Chris Allegretta9956e532000-11-26 02:09:53 +0000182 if (totsize == 0 || fileptr == NULL) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000183 new_file();
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000184 statusbar(_("Read %d lines"), num_lines);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000185 return 1;
186 }
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000187
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000188 if (current != NULL) {
189 fileptr->next = current;
190 current->prev = fileptr;
191 renumber(current);
192 current_x = 0;
193 placewewant = 0;
194 } else if (fileptr->next == NULL) {
195 filebot = fileptr;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000196 new_magicline();
197
198 /* Update the edit buffer */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000199 load_file();
200 }
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000201 statusbar(_("Read %d lines"), num_lines);
202 totlines += num_lines;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000203
204 free(buf);
205 close(fd);
206
207 return 1;
208}
209
210/* Open the file (and decide if it exists) */
211int open_file(char *filename, int insert, int quiet)
212{
213 int fd;
214 struct stat fileinfo;
215
216 if (!strcmp(filename, "") || stat(filename, &fileinfo) == -1) {
217 if (insert) {
218 if (!quiet)
219 statusbar(_("\"%s\" not found"), filename);
220 return -1;
221 } else {
222 /* We have a new file */
223 statusbar(_("New File"));
224 new_file();
225 }
226 } else if ((fd = open(filename, O_RDONLY)) == -1) {
227 if (!quiet)
228 statusbar("%s: %s", strerror(errno), filename);
229 return -1;
230 } else { /* File is A-OK */
231 if (S_ISDIR(fileinfo.st_mode)) {
232 statusbar(_("File \"%s\" is a directory"), filename);
Chris Allegrettaf45c18d2000-09-16 05:25:06 +0000233 if (!insert)
234 new_file();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000235 return -1;
236 }
237 if (!quiet)
238 statusbar(_("Reading File"));
239 read_file(fd, filename);
240 }
241
242 return 1;
243}
244
245int do_insertfile(void)
246{
247 int i;
Chris Allegretta25f4e582000-11-25 05:03:20 +0000248 char *realname = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000249
250 wrap_reset();
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000251 i = statusq(1, writefile_list, WRITEFILE_LIST_LEN, "",
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000252 _("File to insert [from ./] "));
253 if (i != -1) {
254
255#ifdef DEBUG
256 fprintf(stderr, "filename is %s", answer);
257#endif
258
Chris Allegretta09a80842000-11-30 02:31:13 +0000259#ifndef DISABLE_TABCOMP
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000260 realname = real_dir_from_tilde(answer);
Chris Allegretta09a80842000-11-30 02:31:13 +0000261#else
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000262 realname = mallocstrcpy(realname, answer);
Chris Allegretta09a80842000-11-30 02:31:13 +0000263#endif
Chris Allegretta25f4e582000-11-25 05:03:20 +0000264
265 i = open_file(realname, 1, 0);
266 free(realname);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000267
268 dump_buffer(fileage);
269 set_modified();
270
271 /* Here we want to rebuild the edit window */
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000272 fix_editbot();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000273
274 /* If we've gone off the bottom, recenter, otherwise just redraw */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000275 if (current->lineno > editbot->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000276 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000277 else
278 edit_refresh();
279
280 UNSET(KEEP_CUTBUFFER);
281 display_main_list();
282 return i;
283 } else {
284 statusbar(_("Cancelled"));
285 UNSET(KEEP_CUTBUFFER);
286 display_main_list();
287 return 0;
288 }
289}
290
291/*
292 * Write a file out. If tmp is nonzero, we set the umask to 0600,
293 * we don't set the global variable filename to it's name, and don't
294 * print out how many lines we wrote on the statusbar.
295 *
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000296 * tmp means we are writing a tmp file in a secute fashion. We use
297 * it when spell checking or dumping the file on an error.
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000298 */
299int write_file(char *name, int tmp)
300{
301 long size, lineswritten = 0;
302 char buf[PATH_MAX + 1];
303 filestruct *fileptr;
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000304 int fd, mask = 0, realexists, anyexists;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000305 struct stat st, lst, st2;
Chris Allegretta0f5dfef2000-11-24 14:02:57 +0000306 static char *realname = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000307
308 if (!strcmp(name, "")) {
309 statusbar(_("Cancelled"));
310 return -1;
311 }
312 titlebar();
313 fileptr = fileage;
Chris Allegretta0f5dfef2000-11-24 14:02:57 +0000314
315 if (realname != NULL)
316 free(realname);
317
Chris Allegrettabe77c612000-11-24 14:00:16 +0000318#ifndef DISABLE_TABCOMP
319 realname = real_dir_from_tilde(name);
320#else
321 realname = mallocstrcpy(realname, name);
322#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000323
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000324 /* Save the state of file at the end of the symlink (if there is one) */
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000325 realexists = stat(realname, &st);
326
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000327 /* Stat the link itself for the check... */
328 anyexists = lstat(realname, &lst);
Chris Allegrettaacb62342000-07-21 22:42:46 +0000329
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000330 /* New case: if the file exists, just give up */
331 if (tmp && anyexists != -1)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000332 return -1;
Chris Allegrettab5bb24c2000-12-06 00:57:54 +0000333 /* NOTE: If you change this statement, you MUST CHANGE the if
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000334 statement below (that starts "if ((!ISSET(FOLLOW_SYMLINKS)...")
335 to reflect whether or not to link/unlink/rename the file */
336 else if (ISSET(FOLLOW_SYMLINKS) || !S_ISLNK(lst.st_mode) || tmp) {
Chris Allegretta962c3c92000-07-24 21:52:17 +0000337
Chris Allegrettafb2226a2000-12-04 05:25:47 +0000338 /* Use O_EXCL if tmp == 1, I suppose */
339 if (tmp)
340 fd = open(realname, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000341 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |
342 S_IWOTH);
343 else
Chris Allegrettafb2226a2000-12-04 05:25:47 +0000344 fd = open(realname, O_WRONLY | O_CREAT | O_TRUNC,
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000345 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |
346 S_IWOTH);
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000347
348 /* First, just give up if we couldn't even open the file */
Chris Allegretta59828492000-12-04 03:31:39 +0000349 if (fd == -1) {
Chris Allegretta20c131c2000-12-04 04:20:09 +0000350 if (!tmp && ISSET(TEMP_OPT)) {
Chris Allegrettaa299b032000-07-14 02:44:02 +0000351 UNSET(TEMP_OPT);
352 return do_writeout(1);
353 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000354 statusbar(_("Could not open file for writing: %s"),
355 strerror(errno));
Chris Allegrettabe77c612000-11-24 14:00:16 +0000356 free(realname);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000357 return -1;
358 }
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000359
360 /* Now we fstat() the file, to make sure it's the same file still!
361 Thanks to Oliver Friedrichs(?) for this code from securityfocus */
362
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000363 if (fstat(fd, &st2) != 0) {
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000364 close(fd);
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000365 return -1;
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000366 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000367
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000368 }
369 /* Don't follow symlink. Create new file. */
370 else {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000371 if (strlen(realname) > (PATH_MAX - 7)) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000372 statusbar(_("Could not open file: Path length exceeded."));
373 return -1;
374 }
375
376 memset(buf, 0x00, PATH_MAX + 1);
Chris Allegrettabe77c612000-11-24 14:00:16 +0000377 strcat(buf, realname);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000378 strcat(buf, ".XXXXXX");
379 if ((fd = mkstemp(buf)) == -1) {
Chris Allegrettaa299b032000-07-14 02:44:02 +0000380 if (ISSET(TEMP_OPT)) {
381 UNSET(TEMP_OPT);
382 return do_writeout(1);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000383 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000384 statusbar(_("Could not open file for writing: %s"),
385 strerror(errno));
386 return -1;
387 }
388 }
389
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000390 dump_buffer(fileage);
391 while (fileptr != NULL && fileptr->next != NULL) {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000392 /* Next line is so we discount the "magic line" */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000393 if (filebot == fileptr && fileptr->data[0] == '\0')
394 break;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000395
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000396 size = write(fd, fileptr->data, strlen(fileptr->data));
397 if (size == -1) {
398 statusbar(_("Could not open file for writing: %s"),
399 strerror(errno));
400 return -1;
401 } else {
402#ifdef DEBUG
403 fprintf(stderr, _("Wrote >%s\n"), fileptr->data);
404#endif
405 }
406 write(fd, "\n", 1);
407
408 fileptr = fileptr->next;
409 lineswritten++;
410 }
411
412 if (fileptr != NULL) {
413 size = write(fd, fileptr->data, strlen(fileptr->data));
414 if (size == -1) {
415 statusbar(_("Could not open file for writing: %s"),
416 strerror(errno));
417 return -1;
418 } else if (size > 0) {
419 size = write(fd, "\n", 1);
420 if (size == -1) {
421 statusbar(_("Could not open file for writing: %s"),
422 strerror(errno));
423 return -1;
424 }
425 }
426 }
427
428
429 if (close(fd) == -1) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000430 statusbar(_("Could not close %s: %s"), realname, strerror(errno));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000431 unlink(buf);
432 return -1;
433 }
434
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000435 if (realexists == -1 || tmp ||
436 (!ISSET(FOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000437
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000438 /* Use default umask as file permisions if file is a new file. */
439 mask = umask(0);
440 umask(mask);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000441
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000442 if (tmp) /* We don't want anyone reading our temporary file! */
443 mask = 0600;
444 else
445 mask = 0666 & ~mask;
446 } else
Chris Allegrettada13f0b2000-12-06 05:59:31 +0000447 /* Use permissions from file we are overwriting. */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000448 mask = st.st_mode;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000449
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000450 if (!tmp && (!ISSET(FOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000451 if (unlink(realname) == -1) {
452 if (errno != ENOENT) {
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000453 statusbar(_("Could not open %s for writing: %s"),
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000454 realname, strerror(errno));
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000455 unlink(buf);
456 return -1;
457 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000458 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000459 if (link(buf, realname) != -1)
460 unlink(buf);
461 else if (errno != EPERM) {
462 statusbar(_("Could not open %s for writing: %s"),
463 name, strerror(errno));
464 unlink(buf);
465 return -1;
466 } else if (rename(buf, realname) == -1) { /* Try a rename?? */
467 statusbar(_("Could not open %s for writing: %s"),
468 realname, strerror(errno));
469 unlink(buf);
470 return -1;
471 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000472 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000473 if (chmod(realname, mask) == -1)
474 statusbar(_("Could not set permissions %o on %s: %s"),
475 mask, realname, strerror(errno));
476
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000477 if (!tmp) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000478 strncpy(filename, realname, 132);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000479 statusbar(_("Wrote %d lines"), lineswritten);
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000480 UNSET(MODIFIED);
481 titlebar();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000482 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000483 return 1;
484}
485
486int do_writeout(int exiting)
487{
488 int i = 0;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000489#ifdef NANO_EXTRA
490 static int did_cred = 0;
491#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000492
Chris Allegretta92d2bab2000-11-02 14:53:46 +0000493 answer = mallocstrcpy(answer, filename);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000494
Chris Allegretta962c3c92000-07-24 21:52:17 +0000495 if ((exiting) && (ISSET(TEMP_OPT))) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000496 if (filename[0]) {
Chris Allegretta962c3c92000-07-24 21:52:17 +0000497 i = write_file(answer, 0);
498 display_main_list();
499 return i;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000500 } else {
Chris Allegretta461b2a92000-07-24 22:05:18 +0000501 UNSET(TEMP_OPT);
502 do_exit();
503
504 /* They cancelled, abort quit */
505 return -1;
Chris Allegretta962c3c92000-07-24 21:52:17 +0000506 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000507 }
508
509 while (1) {
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000510 i = statusq(1, writefile_list, WRITEFILE_LIST_LEN, answer,
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000511 _("File Name to write"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000512
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000513 if (i != -1) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000514
515#ifdef DEBUG
516 fprintf(stderr, _("filename is %s"), answer);
517#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000518
519#ifdef NANO_EXTRA
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000520 if (exiting && !ISSET(TEMP_OPT) && !strcasecmp(answer, "zzy")
521 && !did_cred) {
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000522 do_credits();
523 did_cred = 1;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000524 return -1;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000525 }
526#endif
Chris Allegretta92d2bab2000-11-02 14:53:46 +0000527 if (strcmp(answer, filename)) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000528 struct stat st;
529 if (!stat(answer, &st)) {
530 i = do_yesno(0, 0, _("File exists, OVERWRITE ?"));
531
532 if (!i || (i == -1))
533 continue;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000534 }
535 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000536 i = write_file(answer, 0);
537
538 display_main_list();
539 return i;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000540 } else {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000541 statusbar(_("Cancelled"));
542 display_main_list();
543 return 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000544 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000545 }
546}
547
548int do_writeout_void(void)
549{
550 return do_writeout(0);
551}
Chris Allegretta04d848e2000-11-05 17:54:41 +0000552
Chris Allegrettabe77c612000-11-24 14:00:16 +0000553#ifndef DISABLE_TABCOMP
554static char **homedirs;
555
556/* Return a malloc()ed string containing the actual directory, used
557 * to convert ~user and ~/ notation...
558 */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000559char *real_dir_from_tilde(char *buf)
Chris Allegrettabe77c612000-11-24 14:00:16 +0000560{
Chris Allegretta04fec912000-11-25 04:43:43 +0000561 char *dirtmp = NULL, *line = NULL, byte[1], *lineptr;
562 int fd, i, status, searchctr = 1;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000563
564 if (buf[0] == '~') {
Chris Allegretta27731842000-11-28 05:53:41 +0000565 if (buf[1] == '~')
566 goto abort; /* Handle ~~ without segfaulting =) */
567 else if (buf[1] == '/') {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000568 if (getenv("HOME") != NULL) {
569 dirtmp = nmalloc(strlen(buf) + 2 + strlen(getenv("HOME")));
570
571 sprintf(dirtmp, "%s/%s", getenv("HOME"), &buf[2]);
572 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000573 } else if (buf[1] != 0) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000574
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000575 if ((fd = open("/etc/passwd", O_RDONLY)) == -1)
Chris Allegretta04fec912000-11-25 04:43:43 +0000576 goto abort;
577
578 /* Figure how how much of of the str we need to compare */
579 for (searchctr = 1; buf[searchctr] != '/' &&
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000580 buf[searchctr] != 0; searchctr++);
Chris Allegretta04fec912000-11-25 04:43:43 +0000581
582 do {
583 i = 0;
584 line = nmalloc(1);
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000585 while ((status = read(fd, byte, 1)) != 0
586 && byte[0] != '\n') {
Chris Allegretta04fec912000-11-25 04:43:43 +0000587
588 line[i] = byte[0];
589 i++;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000590 line = nrealloc(line, i + 1);
Chris Allegretta04fec912000-11-25 04:43:43 +0000591 }
592 line[i] = 0;
593
594 if (i == 0)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000595 goto abort;
Chris Allegretta04fec912000-11-25 04:43:43 +0000596
597 line[i] = 0;
598 lineptr = strtok(line, ":");
599
600 if (!strncmp(lineptr, &buf[1], searchctr - 1)) {
601
602 /* Okay, skip to the password portion now */
603 for (i = 0; i <= 4 && lineptr != NULL; i++)
604 lineptr = strtok(NULL, ":");
605
606 if (lineptr == NULL)
607 goto abort;
608
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000609 /* Else copy the new string into the new buf */
Chris Allegretta04fec912000-11-25 04:43:43 +0000610 dirtmp = nmalloc(strlen(buf) + 2 + strlen(lineptr));
611
612 sprintf(dirtmp, "%s%s", lineptr, &buf[searchctr]);
613 free(line);
614 break;
615 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000616
Chris Allegretta04fec912000-11-25 04:43:43 +0000617 free(line);
618
619 } while (status != 0);
Chris Allegrettabe77c612000-11-24 14:00:16 +0000620 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000621 } else
Chris Allegrettabe77c612000-11-24 14:00:16 +0000622 dirtmp = mallocstrcpy(dirtmp, buf);
623
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000624 return dirtmp;
Chris Allegretta04fec912000-11-25 04:43:43 +0000625
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000626 abort:
Chris Allegretta04fec912000-11-25 04:43:43 +0000627 dirtmp = mallocstrcpy(dirtmp, buf);
628 return dirtmp;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000629}
630
631/* Tack a slash onto the string we're completing if it's a directory */
Chris Allegretta04fec912000-11-25 04:43:43 +0000632int append_slash_if_dir(char *buf, int *lastWasTab, int *place)
Chris Allegrettabe77c612000-11-24 14:00:16 +0000633{
634 char *dirptr;
635 struct stat fileinfo;
Chris Allegretta04fec912000-11-25 04:43:43 +0000636 int ret = 0;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000637
638 dirptr = real_dir_from_tilde(buf);
639
640 if (stat(dirptr, &fileinfo) == -1)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000641 ret = 0;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000642 else if (S_ISDIR(fileinfo.st_mode)) {
643 strncat(buf, "/", 1);
644 *place += 1;
645 /* now we start over again with # of tabs so far */
646 *lastWasTab = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +0000647 ret = 1;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000648 }
649
650 if (dirptr != buf)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000651 free(dirptr);
Chris Allegretta04fec912000-11-25 04:43:43 +0000652
653 return ret;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000654}
Chris Allegretta04d848e2000-11-05 17:54:41 +0000655
656/*
657 * These functions (username_tab_completion, cwd_tab_completion, and
658 * input_tab were taken from busybox 0.46 (cmdedit.c). Here is the notice
659 * from that file:
660 *
661 * Termios command line History and Editting, originally
662 * intended for NetBSD sh (ash)
663 * Copyright (c) 1999
664 * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
665 * Etc: Dave Cinege <dcinege@psychosis.com>
666 * Majorly adjusted/re-written for busybox:
667 * Erik Andersen <andersee@debian.org>
668 *
669 * You may use this code as you wish, so long as the original author(s)
670 * are attributed in any redistributions of the source code.
671 * This code is 'as is' with no warranty.
672 * This code may safely be consumed by a BSD or GPL license.
673 */
674
675char **username_tab_completion(char *buf, int *num_matches)
676{
Chris Allegrettabe77c612000-11-24 14:00:16 +0000677 char **matches = (char **) NULL, *line = NULL, *lineptr;
678 char *matchline = NULL, *matchdir = NULL;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000679
Chris Allegrettabe77c612000-11-24 14:00:16 +0000680 int fd, i = 0, status = 1;
681 char byte[1];
682
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000683 if ((fd = open("/etc/passwd", O_RDONLY)) == -1) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000684 return NULL;
685 }
686
687 if (homedirs != NULL) {
688 for (i = 0; i < *num_matches; i++)
689 free(homedirs[i]);
690 free(homedirs);
691 homedirs = (char **) NULL;
692 *num_matches = 0;
693 }
694 matches = nmalloc(BUFSIZ);
695 homedirs = nmalloc(BUFSIZ);
696 strcat(buf, "*");
697 do {
698 i = 0;
699 line = nmalloc(1);
700 while ((status = read(fd, byte, 1)) != 0 && byte[0] != '\n') {
701
702 line[i] = byte[0];
703 i++;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000704 line = nrealloc(line, i + 1);
Chris Allegrettabe77c612000-11-24 14:00:16 +0000705 }
706
707 if (i == 0)
708 break;
709
710 line[i] = 0;
711 lineptr = strtok(line, ":");
712
713 if (check_wildcard_match(line, &buf[1]) == TRUE) {
714
715 if (*num_matches == BUFSIZ)
716 break;
717
718 /* Cool, found a match. Add it to the list
719 * This makes a lot more sense to me (Chris) this way...
720 */
721 matchline = nmalloc(strlen(line) + 2);
722 sprintf(matchline, "~%s", line);
723
724 for (i = 0; i <= 4 && lineptr != NULL; i++)
725 lineptr = strtok(NULL, ":");
726
727 if (lineptr == NULL)
728 break;
729
730 matchdir = mallocstrcpy(matchdir, lineptr);
731 homedirs[*num_matches] = matchdir;
732 matches[*num_matches] = matchline;
733
734 ++*num_matches;
735
736 /* If there's no more room, bail out */
737 if (*num_matches == BUFSIZ)
738 break;
739 }
740
741 free(line);
742
743 } while (status != 0);
744
745 close(fd);
746 return matches;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000747#ifdef DEBUG
748 fprintf(stderr, "\nin username_tab_completion\n");
749#endif
750 return (matches);
751}
752
753/* This was originally called exe_n_cwd_tab_completion, but we're not
754 worried about executables, only filenames :> */
755
756char **cwd_tab_completion(char *buf, int *num_matches)
757{
Chris Allegrettabe77c612000-11-24 14:00:16 +0000758 char *dirName, *dirtmp = NULL, *tmp = NULL, *tmp2 = NULL;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000759 char **matches = (char **) NULL;
760 DIR *dir;
761 struct dirent *next;
762
Chris Allegretta2c975222000-11-15 01:25:42 +0000763 matches = nmalloc(BUFSIZ);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000764
765 /* Stick a wildcard onto the buf, for later use */
766 strcat(buf, "*");
767
Chris Allegretta2c975222000-11-15 01:25:42 +0000768 /* Okie, if there's a / in the buffer, strip out the directory part */
Chris Allegretta04d848e2000-11-05 17:54:41 +0000769 if (strcmp(buf, "") && strstr(buf, "/")) {
770 dirName = malloc(strlen(buf) + 1);
771 tmp = buf + strlen(buf);
772 while (*tmp != '/' && tmp != buf)
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000773 tmp--;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000774
Chris Allegretta04d848e2000-11-05 17:54:41 +0000775 tmp++;
776
Chris Allegretta442f2c52000-11-14 17:46:06 +0000777 strncpy(dirName, buf, tmp - buf + 1);
778 dirName[tmp - buf] = 0;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000779
Chris Allegretta04d848e2000-11-05 17:54:41 +0000780 } else {
781 if ((dirName = getcwd(NULL, 0)) == NULL)
782 return matches;
783 else
784 tmp = buf;
785 }
786
787#ifdef DEBUG
788 fprintf(stderr, "\nDir = %s\n", dirName);
789 fprintf(stderr, "\nbuf = %s\n", buf);
790 fprintf(stderr, "\ntmp = %s\n", tmp);
791#endif
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000792
Chris Allegrettabe77c612000-11-24 14:00:16 +0000793 dirtmp = real_dir_from_tilde(dirName);
794 free(dirName);
795 dirName = dirtmp;
796
797#ifdef DEBUG
798 fprintf(stderr, "\nDir = %s\n", dirName);
799 fprintf(stderr, "\nbuf = %s\n", buf);
800 fprintf(stderr, "\ntmp = %s\n", tmp);
801#endif
802
803
Chris Allegretta04d848e2000-11-05 17:54:41 +0000804 dir = opendir(dirName);
805 if (!dir) {
806 /* Don't print an error, just shut up and return */
807 *num_matches = 0;
808 beep();
809 return (matches);
810 }
811 while ((next = readdir(dir)) != NULL) {
812
813 /* Some quick sanity checks */
814 if ((strcmp(next->d_name, "..") == 0)
815 || (strcmp(next->d_name, ".") == 0)) {
816 continue;
817 }
818#ifdef DEBUG
Chris Allegretta2c975222000-11-15 01:25:42 +0000819 fprintf(stderr, "Comparing \'%s\'\n", next->d_name);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000820#endif
821 /* See if this matches */
822 if (check_wildcard_match(next->d_name, tmp) == TRUE) {
Chris Allegretta7d97ce72000-11-06 04:04:15 +0000823
824 /* Cool, found a match. Add it to the list
825 * This makes a lot more sense to me (Chris) this way...
826 */
827 tmp2 = NULL;
828 tmp2 = nmalloc(strlen(next->d_name) + 1);
829 strcpy(tmp2, next->d_name);
830 matches[*num_matches] = tmp2;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000831 ++*num_matches;
Chris Allegretta2c975222000-11-15 01:25:42 +0000832
833 /* If there's no more room, bail out */
834 if (*num_matches == BUFSIZ)
835 break;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000836 }
837 }
838
839 return (matches);
840}
841
Chris Allegretta442f2c52000-11-14 17:46:06 +0000842/* This function now has an arg which refers to how much the
Chris Allegretta04d848e2000-11-05 17:54:41 +0000843 * statusbar (place) should be advanced, i.e. the new cursor pos.
844 */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000845char *input_tab(char *buf, int place, int *lastWasTab, int *newplace)
Chris Allegretta04d848e2000-11-05 17:54:41 +0000846{
847 /* Do TAB completion */
Chris Allegrettaec58a992000-11-05 21:54:23 +0000848 static int num_matches = 0, match_matches = 0;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000849 static char **matches = (char **) NULL;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000850 int pos = place, i = 0, col = 0, editline = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +0000851 int longestname = 0, is_dir = 0;
Chris Allegretta3b0d1442000-11-05 21:56:54 +0000852 char *foo;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000853
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000854 if (*lastWasTab == FALSE) {
Chris Allegretta442f2c52000-11-14 17:46:06 +0000855 char *tmp, *copyto, *matchBuf;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000856
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000857 *lastWasTab = 1;
858
Chris Allegretta04d848e2000-11-05 17:54:41 +0000859 /* Make a local copy of the string -- up to the position of the
860 cursor */
Chris Allegrettae118acc2000-11-06 05:40:03 +0000861 matchBuf = (char *) calloc(strlen(buf) + 2, sizeof(char));
862
Chris Allegretta04d848e2000-11-05 17:54:41 +0000863 strncpy(matchBuf, buf, place);
864 tmp = matchBuf;
865
866 /* skip any leading white space */
Chris Allegretta63a89d32000-11-18 03:05:50 +0000867 while (*tmp && isspace((int) *tmp))
Chris Allegretta04d848e2000-11-05 17:54:41 +0000868 ++tmp;
869
870 /* Free up any memory already allocated */
871 if (matches != NULL) {
Chris Allegretta442f2c52000-11-14 17:46:06 +0000872 for (i = i; i < num_matches; i++)
873 free(matches[i]);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000874 free(matches);
875 matches = (char **) NULL;
Chris Allegretta7d97ce72000-11-06 04:04:15 +0000876 num_matches = 0;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000877 }
878
879 /* If the word starts with `~' and there is no slash in the word,
880 * then try completing this word as a username. */
881
Chris Allegrettabe77c612000-11-24 14:00:16 +0000882 /* FIXME -- this check is broken! */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000883 if (*tmp == '~' && !strchr(tmp, '/'))
884 matches = username_tab_completion(tmp, &num_matches);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000885
886 /* Try to match everything in the current working directory that
887 * matches. */
888 if (!matches)
889 matches = cwd_tab_completion(tmp, &num_matches);
890
891 /* Don't leak memory */
892 free(matchBuf);
893
Chris Allegretta442f2c52000-11-14 17:46:06 +0000894#ifdef DEBUG
895 fprintf(stderr, "%d matches found...\n", num_matches);
896#endif
Chris Allegretta04d848e2000-11-05 17:54:41 +0000897 /* Did we find exactly one match? */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000898 switch (num_matches) {
Chris Allegrettae118acc2000-11-06 05:40:03 +0000899 case 0:
Chris Allegretta24342432000-11-06 05:41:20 +0000900 blank_edit();
Chris Allegretta2c975222000-11-15 01:25:42 +0000901 wrefresh(edit);
Chris Allegrettae118acc2000-11-06 05:40:03 +0000902 break;
903 case 1:
Chris Allegretta442f2c52000-11-14 17:46:06 +0000904
905 buf = nrealloc(buf, strlen(buf) + strlen(matches[0]) + 1);
906
907 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000908 for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
909 tmp--);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000910 tmp++;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000911 } else
Chris Allegretta442f2c52000-11-14 17:46:06 +0000912 tmp = buf;
913
Chris Allegretta04fec912000-11-25 04:43:43 +0000914 if (!strcmp(tmp, matches[0]))
915 is_dir = append_slash_if_dir(buf, lastWasTab, newplace);
916
917 if (is_dir)
918 break;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000919
920 copyto = tmp;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000921 for (pos = 0; *tmp == matches[0][pos] &&
922 pos <= strlen(matches[0]); pos++)
Chris Allegretta442f2c52000-11-14 17:46:06 +0000923 tmp++;
924
Chris Allegretta2c975222000-11-15 01:25:42 +0000925 /* write out the matched name */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000926 strncpy(copyto, matches[0], strlen(matches[0]) + 1);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000927 *newplace += strlen(matches[0]) - pos;
928
Chris Allegrettabe77c612000-11-24 14:00:16 +0000929 /* Is it a directory? */
930 append_slash_if_dir(buf, lastWasTab, newplace);
931
Chris Allegrettae118acc2000-11-06 05:40:03 +0000932 break;
933 default:
Chris Allegrettaec58a992000-11-05 21:54:23 +0000934 /* Check to see if all matches share a beginning, and if so
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000935 tack it onto buf and then beep */
Chris Allegrettaec58a992000-11-05 21:54:23 +0000936
Chris Allegretta442f2c52000-11-14 17:46:06 +0000937 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000938 for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
939 tmp--);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000940 tmp++;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000941 } else
Chris Allegretta442f2c52000-11-14 17:46:06 +0000942 tmp = buf;
943
944 for (pos = 0; *tmp == matches[0][pos] && *tmp != 0 &&
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000945 pos <= strlen(matches[0]); pos++)
Chris Allegretta442f2c52000-11-14 17:46:06 +0000946 tmp++;
947
Chris Allegrettaec58a992000-11-05 21:54:23 +0000948 while (1) {
949 match_matches = 0;
950
951 for (i = 0; i < num_matches; i++) {
952 if (matches[i][pos] == 0)
953 break;
954 else if (matches[i][pos] == matches[0][pos])
955 match_matches++;
956 }
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000957 if (match_matches == num_matches &&
958 (i == num_matches || matches[i] != 0)) {
Chris Allegrettaec58a992000-11-05 21:54:23 +0000959 /* All the matches have the same character at pos+1,
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000960 so paste it into buf... */
Chris Allegretta75864952000-11-05 22:48:35 +0000961 buf = nrealloc(buf, strlen(buf) + 2);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000962 strncat(buf, matches[0] + pos, 1);
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000963 *newplace += 1;
Chris Allegrettaec58a992000-11-05 21:54:23 +0000964 pos++;
Chris Allegretta75864952000-11-05 22:48:35 +0000965 } else {
Chris Allegrettaec58a992000-11-05 21:54:23 +0000966 beep();
967 break;
968 }
969 }
Chris Allegrettae118acc2000-11-06 05:40:03 +0000970 break;
Chris Allegrettaec58a992000-11-05 21:54:23 +0000971 }
Chris Allegretta04d848e2000-11-05 17:54:41 +0000972 } else {
973 /* Ok -- the last char was a TAB. Since they
974 * just hit TAB again, print a list of all the
975 * available choices... */
976 if (matches && num_matches > 0) {
Chris Allegretta04d848e2000-11-05 17:54:41 +0000977
978 /* Blank the edit window, and print the matches out there */
979 blank_edit();
980 wmove(edit, 0, 0);
981
Chris Allegrettaec58a992000-11-05 21:54:23 +0000982 editline = 0;
Chris Allegretta2c975222000-11-15 01:25:42 +0000983
Chris Allegrettaec58a992000-11-05 21:54:23 +0000984 /* Figure out the length of the longest filename */
985 for (i = 0; i < num_matches; i++)
986 if (strlen(matches[i]) > longestname)
987 longestname = strlen(matches[i]);
988
989 if (longestname > COLS - 1)
990 longestname = COLS - 1;
991
Chris Allegretta3b0d1442000-11-05 21:56:54 +0000992 foo = nmalloc(longestname + 5);
993
Chris Allegretta04d848e2000-11-05 17:54:41 +0000994 /* Print the list of matches */
995 for (i = 0, col = 0; i < num_matches; i++) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000996
Chris Allegrettaec58a992000-11-05 21:54:23 +0000997 /* make each filename shown be the same length as the longest
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000998 filename, with two spaces at the end */
Chris Allegrettaec58a992000-11-05 21:54:23 +0000999 snprintf(foo, longestname + 1, matches[i]);
1000 while (strlen(foo) < longestname)
1001 strcat(foo, " ");
1002
1003 strcat(foo, " ");
1004
Chris Allegretta442f2c52000-11-14 17:46:06 +00001005 /* Disable el cursor */
1006 curs_set(0);
Chris Allegretta75864952000-11-05 22:48:35 +00001007 /* now, put the match on the screen */
1008 waddnstr(edit, foo, strlen(foo));
1009 col += strlen(foo);
1010
1011 /* And if the next match isn't going to fit on the
1012 line, move to the next one */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001013 if (col > (COLS - longestname) && matches[i + 1] != NULL) {
Chris Allegrettaec58a992000-11-05 21:54:23 +00001014 editline++;
1015 wmove(edit, editline, 0);
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001016 if (editline == editwinrows - 1) {
1017 waddstr(edit, _("(more)"));
1018 break;
1019 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001020 col = 0;
1021 }
1022 }
Chris Allegretta3b0d1442000-11-05 21:56:54 +00001023 free(foo);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001024 wrefresh(edit);
Chris Allegretta24dd8d62000-11-06 05:45:48 +00001025 } else
1026 beep();
Chris Allegretta04d848e2000-11-05 17:54:41 +00001027
1028 }
1029
1030 edit_refresh();
Chris Allegretta442f2c52000-11-14 17:46:06 +00001031 curs_set(1);
1032 return buf;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001033}
Chris Allegrettabe77c612000-11-24 14:00:16 +00001034#endif