blob: c39a482adea159679439dce7fa43b01231599160 [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();
Chris Allegretta321590a2000-12-10 06:03:40 +0000197 totsize--;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000198
199 /* Update the edit buffer */
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000200 load_file();
201 }
Adam Rogoyski1e328fb2000-07-08 03:57:16 +0000202 statusbar(_("Read %d lines"), num_lines);
203 totlines += num_lines;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000204
205 free(buf);
206 close(fd);
207
208 return 1;
209}
210
211/* Open the file (and decide if it exists) */
212int open_file(char *filename, int insert, int quiet)
213{
214 int fd;
215 struct stat fileinfo;
216
217 if (!strcmp(filename, "") || stat(filename, &fileinfo) == -1) {
218 if (insert) {
219 if (!quiet)
220 statusbar(_("\"%s\" not found"), filename);
221 return -1;
222 } else {
223 /* We have a new file */
224 statusbar(_("New File"));
225 new_file();
226 }
227 } else if ((fd = open(filename, O_RDONLY)) == -1) {
228 if (!quiet)
229 statusbar("%s: %s", strerror(errno), filename);
Chris Allegretta3a7c0be2000-12-18 01:09:07 +0000230 if (!insert)
231 new_file();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000232 return -1;
233 } else { /* File is A-OK */
Chris Allegretta7960dcf2000-12-13 15:01:29 +0000234 if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
235 S_ISBLK(fileinfo.st_mode)) {
236 if (S_ISDIR(fileinfo.st_mode))
237 statusbar(_("File \"%s\" is a directory"), filename);
238 else
239 /* Don't open character or block files. Sorry, /dev/sndstat! */
240 statusbar(_("File \"%s\" is a device file"), filename);
241
Chris Allegrettaf45c18d2000-09-16 05:25:06 +0000242 if (!insert)
243 new_file();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000244 return -1;
245 }
246 if (!quiet)
247 statusbar(_("Reading File"));
248 read_file(fd, filename);
249 }
250
251 return 1;
252}
253
254int do_insertfile(void)
255{
256 int i;
Chris Allegretta25f4e582000-11-25 05:03:20 +0000257 char *realname = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000258
259 wrap_reset();
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000260 i = statusq(1, writefile_list, WRITEFILE_LIST_LEN, "",
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000261 _("File to insert [from ./] "));
262 if (i != -1) {
263
264#ifdef DEBUG
265 fprintf(stderr, "filename is %s", answer);
266#endif
267
Chris Allegretta09a80842000-11-30 02:31:13 +0000268#ifndef DISABLE_TABCOMP
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000269 realname = real_dir_from_tilde(answer);
Chris Allegretta09a80842000-11-30 02:31:13 +0000270#else
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000271 realname = mallocstrcpy(realname, answer);
Chris Allegretta09a80842000-11-30 02:31:13 +0000272#endif
Chris Allegretta25f4e582000-11-25 05:03:20 +0000273
274 i = open_file(realname, 1, 0);
275 free(realname);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000276
277 dump_buffer(fileage);
278 set_modified();
279
280 /* Here we want to rebuild the edit window */
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000281 fix_editbot();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000282
283 /* If we've gone off the bottom, recenter, otherwise just redraw */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000284 if (current->lineno > editbot->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000285 edit_update(current, CENTER);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000286 else
287 edit_refresh();
288
289 UNSET(KEEP_CUTBUFFER);
290 display_main_list();
291 return i;
292 } else {
293 statusbar(_("Cancelled"));
294 UNSET(KEEP_CUTBUFFER);
295 display_main_list();
296 return 0;
297 }
298}
299
300/*
301 * Write a file out. If tmp is nonzero, we set the umask to 0600,
302 * we don't set the global variable filename to it's name, and don't
303 * print out how many lines we wrote on the statusbar.
304 *
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000305 * tmp means we are writing a tmp file in a secute fashion. We use
306 * it when spell checking or dumping the file on an error.
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000307 */
308int write_file(char *name, int tmp)
309{
310 long size, lineswritten = 0;
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000311 static char *buf = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000312 filestruct *fileptr;
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000313 int fd, mask = 0, realexists, anyexists;
Chris Allegretta7960dcf2000-12-13 15:01:29 +0000314 struct stat st, lst;
Chris Allegretta0f5dfef2000-11-24 14:02:57 +0000315 static char *realname = NULL;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000316
317 if (!strcmp(name, "")) {
318 statusbar(_("Cancelled"));
319 return -1;
320 }
321 titlebar();
322 fileptr = fileage;
Chris Allegretta0f5dfef2000-11-24 14:02:57 +0000323
324 if (realname != NULL)
325 free(realname);
326
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000327 if (buf != NULL)
328 free(buf);
329
Chris Allegrettabe77c612000-11-24 14:00:16 +0000330#ifndef DISABLE_TABCOMP
331 realname = real_dir_from_tilde(name);
332#else
333 realname = mallocstrcpy(realname, name);
334#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000335
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000336 /* Save the state of file at the end of the symlink (if there is one) */
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000337 realexists = stat(realname, &st);
338
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000339 /* Stat the link itself for the check... */
340 anyexists = lstat(realname, &lst);
Chris Allegrettaacb62342000-07-21 22:42:46 +0000341
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000342 /* New case: if the file exists, just give up */
343 if (tmp && anyexists != -1)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000344 return -1;
Chris Allegrettab5bb24c2000-12-06 00:57:54 +0000345 /* NOTE: If you change this statement, you MUST CHANGE the if
Chris Allegretta544d9b02000-12-11 02:47:13 +0000346 statement below (that says:
347 if (realexists == -1 || tmp || (!ISSET(FOLLOW_SYMLINKS) &&
348 S_ISLNK(lst.st_mode))) {
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000349 to reflect whether or not to link/unlink/rename the file */
350 else if (ISSET(FOLLOW_SYMLINKS) || !S_ISLNK(lst.st_mode) || tmp) {
Chris Allegretta33084392000-12-09 22:50:38 +0000351 /* Use O_EXCL if tmp == 1. This is now copied from joe, because
Chris Allegrettaf5977772000-12-09 23:58:41 +0000352 wiggy says so *shrug*. */
353 if (tmp)
354 fd = open(realname, O_WRONLY | O_CREAT | O_EXCL, (S_IRUSR|S_IWUSR));
355 else
356 fd = open(realname, O_WRONLY | O_CREAT | O_TRUNC, (S_IRUSR|S_IWUSR));
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000357
358 /* First, just give up if we couldn't even open the file */
Chris Allegretta59828492000-12-04 03:31:39 +0000359 if (fd == -1) {
Chris Allegretta20c131c2000-12-04 04:20:09 +0000360 if (!tmp && ISSET(TEMP_OPT)) {
Chris Allegrettaa299b032000-07-14 02:44:02 +0000361 UNSET(TEMP_OPT);
362 return do_writeout(1);
363 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000364 statusbar(_("Could not open file for writing: %s"),
365 strerror(errno));
Chris Allegrettabe77c612000-11-24 14:00:16 +0000366 free(realname);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000367 return -1;
368 }
Chris Allegretta07f9ee02000-12-04 05:15:39 +0000369
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000370 }
371 /* Don't follow symlink. Create new file. */
372 else {
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000373 buf = nmalloc(strlen(realname) + 8);
374 strncpy(buf, realname, strlen(realname)+1);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000375 strcat(buf, ".XXXXXX");
376 if ((fd = mkstemp(buf)) == -1) {
Chris Allegrettaa299b032000-07-14 02:44:02 +0000377 if (ISSET(TEMP_OPT)) {
378 UNSET(TEMP_OPT);
379 return do_writeout(1);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000380 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000381 statusbar(_("Could not open file for writing: %s"),
382 strerror(errno));
383 return -1;
384 }
385 }
386
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000387 dump_buffer(fileage);
388 while (fileptr != NULL && fileptr->next != NULL) {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000389 /* Next line is so we discount the "magic line" */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000390 if (filebot == fileptr && fileptr->data[0] == '\0')
391 break;
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000392
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000393 size = write(fd, fileptr->data, strlen(fileptr->data));
394 if (size == -1) {
395 statusbar(_("Could not open file for writing: %s"),
396 strerror(errno));
397 return -1;
398 } else {
399#ifdef DEBUG
400 fprintf(stderr, _("Wrote >%s\n"), fileptr->data);
401#endif
402 }
403 write(fd, "\n", 1);
404
405 fileptr = fileptr->next;
406 lineswritten++;
407 }
408
409 if (fileptr != NULL) {
410 size = write(fd, fileptr->data, strlen(fileptr->data));
411 if (size == -1) {
412 statusbar(_("Could not open file for writing: %s"),
413 strerror(errno));
414 return -1;
415 } else if (size > 0) {
416 size = write(fd, "\n", 1);
417 if (size == -1) {
418 statusbar(_("Could not open file for writing: %s"),
419 strerror(errno));
420 return -1;
421 }
422 }
423 }
424
425
426 if (close(fd) == -1) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000427 statusbar(_("Could not close %s: %s"), realname, strerror(errno));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000428 unlink(buf);
429 return -1;
430 }
431
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000432 if (realexists == -1 || tmp ||
433 (!ISSET(FOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000434
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000435 /* Use default umask as file permisions if file is a new file. */
436 mask = umask(0);
437 umask(mask);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000438
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000439 if (tmp) /* We don't want anyone reading our temporary file! */
440 mask = 0600;
441 else
442 mask = 0666 & ~mask;
443 } else
Chris Allegrettada13f0b2000-12-06 05:59:31 +0000444 /* Use permissions from file we are overwriting. */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000445 mask = st.st_mode;
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000446
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000447 if (!tmp && (!ISSET(FOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000448 if (unlink(realname) == -1) {
449 if (errno != ENOENT) {
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000450 statusbar(_("Could not open %s for writing: %s"),
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000451 realname, strerror(errno));
Chris Allegrettaf7ee9e62000-12-02 21:13:50 +0000452 unlink(buf);
453 return -1;
454 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000455 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000456 if (link(buf, realname) != -1)
457 unlink(buf);
458 else if (errno != EPERM) {
459 statusbar(_("Could not open %s for writing: %s"),
460 name, strerror(errno));
461 unlink(buf);
462 return -1;
463 } else if (rename(buf, realname) == -1) { /* Try a rename?? */
464 statusbar(_("Could not open %s for writing: %s"),
465 realname, strerror(errno));
466 unlink(buf);
467 return -1;
468 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000469 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000470 if (chmod(realname, mask) == -1)
471 statusbar(_("Could not set permissions %o on %s: %s"),
472 mask, realname, strerror(errno));
473
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000474 if (!tmp) {
Chris Allegretta1a6e9042000-12-14 13:56:28 +0000475 filename = mallocstrcpy(filename, realname);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000476 statusbar(_("Wrote %d lines"), lineswritten);
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000477 UNSET(MODIFIED);
478 titlebar();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000479 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000480 return 1;
481}
482
483int do_writeout(int exiting)
484{
485 int i = 0;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000486#ifdef NANO_EXTRA
487 static int did_cred = 0;
488#endif
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000489
Chris Allegretta92d2bab2000-11-02 14:53:46 +0000490 answer = mallocstrcpy(answer, filename);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000491
Chris Allegretta962c3c92000-07-24 21:52:17 +0000492 if ((exiting) && (ISSET(TEMP_OPT))) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000493 if (filename[0]) {
Chris Allegretta962c3c92000-07-24 21:52:17 +0000494 i = write_file(answer, 0);
495 display_main_list();
496 return i;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000497 } else {
Chris Allegretta461b2a92000-07-24 22:05:18 +0000498 UNSET(TEMP_OPT);
499 do_exit();
500
501 /* They cancelled, abort quit */
502 return -1;
Chris Allegretta962c3c92000-07-24 21:52:17 +0000503 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000504 }
505
506 while (1) {
Chris Allegretta7da4e9f2000-11-06 02:57:22 +0000507 i = statusq(1, writefile_list, WRITEFILE_LIST_LEN, answer,
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000508 _("File Name to write"));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000509
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000510 if (i != -1) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000511
512#ifdef DEBUG
513 fprintf(stderr, _("filename is %s"), answer);
514#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000515
516#ifdef NANO_EXTRA
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000517 if (exiting && !ISSET(TEMP_OPT) && !strcasecmp(answer, "zzy")
518 && !did_cred) {
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000519 do_credits();
520 did_cred = 1;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000521 return -1;
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000522 }
523#endif
Chris Allegretta92d2bab2000-11-02 14:53:46 +0000524 if (strcmp(answer, filename)) {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000525 struct stat st;
526 if (!stat(answer, &st)) {
527 i = do_yesno(0, 0, _("File exists, OVERWRITE ?"));
528
529 if (!i || (i == -1))
530 continue;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000531 }
532 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000533 i = write_file(answer, 0);
534
535 display_main_list();
536 return i;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000537 } else {
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000538 statusbar(_("Cancelled"));
539 display_main_list();
540 return 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000541 }
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000542 }
543}
544
545int do_writeout_void(void)
546{
547 return do_writeout(0);
548}
Chris Allegretta04d848e2000-11-05 17:54:41 +0000549
Chris Allegrettabe77c612000-11-24 14:00:16 +0000550#ifndef DISABLE_TABCOMP
551static char **homedirs;
552
553/* Return a malloc()ed string containing the actual directory, used
554 * to convert ~user and ~/ notation...
555 */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000556char *real_dir_from_tilde(char *buf)
Chris Allegrettabe77c612000-11-24 14:00:16 +0000557{
Chris Allegretta04fec912000-11-25 04:43:43 +0000558 char *dirtmp = NULL, *line = NULL, byte[1], *lineptr;
559 int fd, i, status, searchctr = 1;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000560
561 if (buf[0] == '~') {
Chris Allegretta27731842000-11-28 05:53:41 +0000562 if (buf[1] == '~')
563 goto abort; /* Handle ~~ without segfaulting =) */
564 else if (buf[1] == '/') {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000565 if (getenv("HOME") != NULL) {
566 dirtmp = nmalloc(strlen(buf) + 2 + strlen(getenv("HOME")));
567
568 sprintf(dirtmp, "%s/%s", getenv("HOME"), &buf[2]);
569 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000570 } else if (buf[1] != 0) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000571
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000572 if ((fd = open("/etc/passwd", O_RDONLY)) == -1)
Chris Allegretta04fec912000-11-25 04:43:43 +0000573 goto abort;
574
575 /* Figure how how much of of the str we need to compare */
576 for (searchctr = 1; buf[searchctr] != '/' &&
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000577 buf[searchctr] != 0; searchctr++);
Chris Allegretta04fec912000-11-25 04:43:43 +0000578
579 do {
580 i = 0;
581 line = nmalloc(1);
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000582 while ((status = read(fd, byte, 1)) != 0
583 && byte[0] != '\n') {
Chris Allegretta04fec912000-11-25 04:43:43 +0000584
585 line[i] = byte[0];
586 i++;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000587 line = nrealloc(line, i + 1);
Chris Allegretta04fec912000-11-25 04:43:43 +0000588 }
589 line[i] = 0;
590
591 if (i == 0)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000592 goto abort;
Chris Allegretta04fec912000-11-25 04:43:43 +0000593
594 line[i] = 0;
595 lineptr = strtok(line, ":");
596
597 if (!strncmp(lineptr, &buf[1], searchctr - 1)) {
598
599 /* Okay, skip to the password portion now */
600 for (i = 0; i <= 4 && lineptr != NULL; i++)
601 lineptr = strtok(NULL, ":");
602
603 if (lineptr == NULL)
604 goto abort;
605
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000606 /* Else copy the new string into the new buf */
Chris Allegretta04fec912000-11-25 04:43:43 +0000607 dirtmp = nmalloc(strlen(buf) + 2 + strlen(lineptr));
608
609 sprintf(dirtmp, "%s%s", lineptr, &buf[searchctr]);
610 free(line);
611 break;
612 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000613
Chris Allegretta04fec912000-11-25 04:43:43 +0000614 free(line);
615
616 } while (status != 0);
Chris Allegrettabe77c612000-11-24 14:00:16 +0000617 }
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000618 } else
Chris Allegrettabe77c612000-11-24 14:00:16 +0000619 dirtmp = mallocstrcpy(dirtmp, buf);
620
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000621 return dirtmp;
Chris Allegretta04fec912000-11-25 04:43:43 +0000622
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000623 abort:
Chris Allegretta04fec912000-11-25 04:43:43 +0000624 dirtmp = mallocstrcpy(dirtmp, buf);
625 return dirtmp;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000626}
627
628/* Tack a slash onto the string we're completing if it's a directory */
Chris Allegretta04fec912000-11-25 04:43:43 +0000629int append_slash_if_dir(char *buf, int *lastWasTab, int *place)
Chris Allegrettabe77c612000-11-24 14:00:16 +0000630{
631 char *dirptr;
632 struct stat fileinfo;
Chris Allegretta04fec912000-11-25 04:43:43 +0000633 int ret = 0;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000634
635 dirptr = real_dir_from_tilde(buf);
636
637 if (stat(dirptr, &fileinfo) == -1)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000638 ret = 0;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000639 else if (S_ISDIR(fileinfo.st_mode)) {
640 strncat(buf, "/", 1);
641 *place += 1;
642 /* now we start over again with # of tabs so far */
643 *lastWasTab = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +0000644 ret = 1;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000645 }
646
647 if (dirptr != buf)
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000648 free(dirptr);
Chris Allegretta04fec912000-11-25 04:43:43 +0000649
650 return ret;
Chris Allegrettabe77c612000-11-24 14:00:16 +0000651}
Chris Allegretta04d848e2000-11-05 17:54:41 +0000652
653/*
654 * These functions (username_tab_completion, cwd_tab_completion, and
655 * input_tab were taken from busybox 0.46 (cmdedit.c). Here is the notice
656 * from that file:
657 *
658 * Termios command line History and Editting, originally
659 * intended for NetBSD sh (ash)
660 * Copyright (c) 1999
661 * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
662 * Etc: Dave Cinege <dcinege@psychosis.com>
663 * Majorly adjusted/re-written for busybox:
664 * Erik Andersen <andersee@debian.org>
665 *
666 * You may use this code as you wish, so long as the original author(s)
667 * are attributed in any redistributions of the source code.
668 * This code is 'as is' with no warranty.
669 * This code may safely be consumed by a BSD or GPL license.
670 */
671
672char **username_tab_completion(char *buf, int *num_matches)
673{
Chris Allegrettabe77c612000-11-24 14:00:16 +0000674 char **matches = (char **) NULL, *line = NULL, *lineptr;
675 char *matchline = NULL, *matchdir = NULL;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000676
Chris Allegrettabe77c612000-11-24 14:00:16 +0000677 int fd, i = 0, status = 1;
678 char byte[1];
679
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000680 if ((fd = open("/etc/passwd", O_RDONLY)) == -1) {
Chris Allegrettabe77c612000-11-24 14:00:16 +0000681 return NULL;
682 }
683
684 if (homedirs != NULL) {
685 for (i = 0; i < *num_matches; i++)
686 free(homedirs[i]);
687 free(homedirs);
688 homedirs = (char **) NULL;
689 *num_matches = 0;
690 }
691 matches = nmalloc(BUFSIZ);
692 homedirs = nmalloc(BUFSIZ);
693 strcat(buf, "*");
694 do {
695 i = 0;
696 line = nmalloc(1);
697 while ((status = read(fd, byte, 1)) != 0 && byte[0] != '\n') {
698
699 line[i] = byte[0];
700 i++;
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000701 line = nrealloc(line, i + 1);
Chris Allegrettabe77c612000-11-24 14:00:16 +0000702 }
703
704 if (i == 0)
705 break;
706
707 line[i] = 0;
708 lineptr = strtok(line, ":");
709
710 if (check_wildcard_match(line, &buf[1]) == TRUE) {
711
712 if (*num_matches == BUFSIZ)
713 break;
714
715 /* Cool, found a match. Add it to the list
716 * This makes a lot more sense to me (Chris) this way...
717 */
718 matchline = nmalloc(strlen(line) + 2);
719 sprintf(matchline, "~%s", line);
720
721 for (i = 0; i <= 4 && lineptr != NULL; i++)
722 lineptr = strtok(NULL, ":");
723
724 if (lineptr == NULL)
725 break;
726
727 matchdir = mallocstrcpy(matchdir, lineptr);
728 homedirs[*num_matches] = matchdir;
729 matches[*num_matches] = matchline;
730
731 ++*num_matches;
732
733 /* If there's no more room, bail out */
734 if (*num_matches == BUFSIZ)
735 break;
736 }
737
738 free(line);
739
740 } while (status != 0);
741
742 close(fd);
743 return matches;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000744#ifdef DEBUG
745 fprintf(stderr, "\nin username_tab_completion\n");
746#endif
747 return (matches);
748}
749
750/* This was originally called exe_n_cwd_tab_completion, but we're not
751 worried about executables, only filenames :> */
752
753char **cwd_tab_completion(char *buf, int *num_matches)
754{
Chris Allegrettabe77c612000-11-24 14:00:16 +0000755 char *dirName, *dirtmp = NULL, *tmp = NULL, *tmp2 = NULL;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000756 char **matches = (char **) NULL;
757 DIR *dir;
758 struct dirent *next;
759
Chris Allegretta2c975222000-11-15 01:25:42 +0000760 matches = nmalloc(BUFSIZ);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000761
762 /* Stick a wildcard onto the buf, for later use */
763 strcat(buf, "*");
764
Chris Allegretta2c975222000-11-15 01:25:42 +0000765 /* Okie, if there's a / in the buffer, strip out the directory part */
Chris Allegretta04d848e2000-11-05 17:54:41 +0000766 if (strcmp(buf, "") && strstr(buf, "/")) {
767 dirName = malloc(strlen(buf) + 1);
768 tmp = buf + strlen(buf);
769 while (*tmp != '/' && tmp != buf)
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000770 tmp--;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000771
Chris Allegretta04d848e2000-11-05 17:54:41 +0000772 tmp++;
773
Chris Allegretta442f2c52000-11-14 17:46:06 +0000774 strncpy(dirName, buf, tmp - buf + 1);
775 dirName[tmp - buf] = 0;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000776
Chris Allegretta04d848e2000-11-05 17:54:41 +0000777 } else {
778 if ((dirName = getcwd(NULL, 0)) == NULL)
779 return matches;
780 else
781 tmp = buf;
782 }
783
784#ifdef DEBUG
785 fprintf(stderr, "\nDir = %s\n", dirName);
786 fprintf(stderr, "\nbuf = %s\n", buf);
787 fprintf(stderr, "\ntmp = %s\n", tmp);
788#endif
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000789
Chris Allegrettabe77c612000-11-24 14:00:16 +0000790 dirtmp = real_dir_from_tilde(dirName);
791 free(dirName);
792 dirName = dirtmp;
793
794#ifdef DEBUG
795 fprintf(stderr, "\nDir = %s\n", dirName);
796 fprintf(stderr, "\nbuf = %s\n", buf);
797 fprintf(stderr, "\ntmp = %s\n", tmp);
798#endif
799
800
Chris Allegretta04d848e2000-11-05 17:54:41 +0000801 dir = opendir(dirName);
802 if (!dir) {
803 /* Don't print an error, just shut up and return */
804 *num_matches = 0;
805 beep();
806 return (matches);
807 }
808 while ((next = readdir(dir)) != NULL) {
809
810 /* Some quick sanity checks */
811 if ((strcmp(next->d_name, "..") == 0)
812 || (strcmp(next->d_name, ".") == 0)) {
813 continue;
814 }
815#ifdef DEBUG
Chris Allegretta2c975222000-11-15 01:25:42 +0000816 fprintf(stderr, "Comparing \'%s\'\n", next->d_name);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000817#endif
818 /* See if this matches */
819 if (check_wildcard_match(next->d_name, tmp) == TRUE) {
Chris Allegretta7d97ce72000-11-06 04:04:15 +0000820
821 /* Cool, found a match. Add it to the list
822 * This makes a lot more sense to me (Chris) this way...
823 */
824 tmp2 = NULL;
825 tmp2 = nmalloc(strlen(next->d_name) + 1);
826 strcpy(tmp2, next->d_name);
827 matches[*num_matches] = tmp2;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000828 ++*num_matches;
Chris Allegretta2c975222000-11-15 01:25:42 +0000829
830 /* If there's no more room, bail out */
831 if (*num_matches == BUFSIZ)
832 break;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000833 }
834 }
835
836 return (matches);
837}
838
Chris Allegretta442f2c52000-11-14 17:46:06 +0000839/* This function now has an arg which refers to how much the
Chris Allegretta04d848e2000-11-05 17:54:41 +0000840 * statusbar (place) should be advanced, i.e. the new cursor pos.
841 */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000842char *input_tab(char *buf, int place, int *lastWasTab, int *newplace)
Chris Allegretta04d848e2000-11-05 17:54:41 +0000843{
844 /* Do TAB completion */
Chris Allegrettaec58a992000-11-05 21:54:23 +0000845 static int num_matches = 0, match_matches = 0;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000846 static char **matches = (char **) NULL;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000847 int pos = place, i = 0, col = 0, editline = 0;
Chris Allegretta04fec912000-11-25 04:43:43 +0000848 int longestname = 0, is_dir = 0;
Chris Allegretta3b0d1442000-11-05 21:56:54 +0000849 char *foo;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000850
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000851 if (*lastWasTab == FALSE) {
Chris Allegretta442f2c52000-11-14 17:46:06 +0000852 char *tmp, *copyto, *matchBuf;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000853
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000854 *lastWasTab = 1;
855
Chris Allegretta04d848e2000-11-05 17:54:41 +0000856 /* Make a local copy of the string -- up to the position of the
857 cursor */
Chris Allegrettae118acc2000-11-06 05:40:03 +0000858 matchBuf = (char *) calloc(strlen(buf) + 2, sizeof(char));
859
Chris Allegretta04d848e2000-11-05 17:54:41 +0000860 strncpy(matchBuf, buf, place);
861 tmp = matchBuf;
862
863 /* skip any leading white space */
Chris Allegretta63a89d32000-11-18 03:05:50 +0000864 while (*tmp && isspace((int) *tmp))
Chris Allegretta04d848e2000-11-05 17:54:41 +0000865 ++tmp;
866
867 /* Free up any memory already allocated */
868 if (matches != NULL) {
Chris Allegretta442f2c52000-11-14 17:46:06 +0000869 for (i = i; i < num_matches; i++)
870 free(matches[i]);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000871 free(matches);
872 matches = (char **) NULL;
Chris Allegretta7d97ce72000-11-06 04:04:15 +0000873 num_matches = 0;
Chris Allegretta04d848e2000-11-05 17:54:41 +0000874 }
875
876 /* If the word starts with `~' and there is no slash in the word,
877 * then try completing this word as a username. */
878
Chris Allegrettabe77c612000-11-24 14:00:16 +0000879 /* FIXME -- this check is broken! */
Chris Allegretta1bd0ce22000-12-06 05:56:08 +0000880 if (*tmp == '~' && !strchr(tmp, '/'))
881 matches = username_tab_completion(tmp, &num_matches);
Chris Allegretta04d848e2000-11-05 17:54:41 +0000882
883 /* Try to match everything in the current working directory that
884 * matches. */
885 if (!matches)
886 matches = cwd_tab_completion(tmp, &num_matches);
887
888 /* Don't leak memory */
889 free(matchBuf);
890
Chris Allegretta442f2c52000-11-14 17:46:06 +0000891#ifdef DEBUG
892 fprintf(stderr, "%d matches found...\n", num_matches);
893#endif
Chris Allegretta04d848e2000-11-05 17:54:41 +0000894 /* Did we find exactly one match? */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000895 switch (num_matches) {
Chris Allegrettae118acc2000-11-06 05:40:03 +0000896 case 0:
Chris Allegretta24342432000-11-06 05:41:20 +0000897 blank_edit();
Chris Allegretta2c975222000-11-15 01:25:42 +0000898 wrefresh(edit);
Chris Allegrettae118acc2000-11-06 05:40:03 +0000899 break;
900 case 1:
Chris Allegretta442f2c52000-11-14 17:46:06 +0000901
902 buf = nrealloc(buf, strlen(buf) + strlen(matches[0]) + 1);
903
904 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000905 for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
906 tmp--);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000907 tmp++;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000908 } else
Chris Allegretta442f2c52000-11-14 17:46:06 +0000909 tmp = buf;
910
Chris Allegretta04fec912000-11-25 04:43:43 +0000911 if (!strcmp(tmp, matches[0]))
912 is_dir = append_slash_if_dir(buf, lastWasTab, newplace);
913
914 if (is_dir)
915 break;
Chris Allegretta442f2c52000-11-14 17:46:06 +0000916
917 copyto = tmp;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000918 for (pos = 0; *tmp == matches[0][pos] &&
919 pos <= strlen(matches[0]); pos++)
Chris Allegretta442f2c52000-11-14 17:46:06 +0000920 tmp++;
921
Chris Allegretta2c975222000-11-15 01:25:42 +0000922 /* write out the matched name */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000923 strncpy(copyto, matches[0], strlen(matches[0]) + 1);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000924 *newplace += strlen(matches[0]) - pos;
925
Chris Allegrettabe77c612000-11-24 14:00:16 +0000926 /* Is it a directory? */
927 append_slash_if_dir(buf, lastWasTab, newplace);
928
Chris Allegrettae118acc2000-11-06 05:40:03 +0000929 break;
930 default:
Chris Allegrettaec58a992000-11-05 21:54:23 +0000931 /* Check to see if all matches share a beginning, and if so
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000932 tack it onto buf and then beep */
Chris Allegrettaec58a992000-11-05 21:54:23 +0000933
Chris Allegretta442f2c52000-11-14 17:46:06 +0000934 if (strcmp(buf, "") && strstr(buf, "/")) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000935 for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
936 tmp--);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000937 tmp++;
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000938 } else
Chris Allegretta442f2c52000-11-14 17:46:06 +0000939 tmp = buf;
940
941 for (pos = 0; *tmp == matches[0][pos] && *tmp != 0 &&
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000942 pos <= strlen(matches[0]); pos++)
Chris Allegretta442f2c52000-11-14 17:46:06 +0000943 tmp++;
944
Chris Allegrettaec58a992000-11-05 21:54:23 +0000945 while (1) {
946 match_matches = 0;
947
948 for (i = 0; i < num_matches; i++) {
949 if (matches[i][pos] == 0)
950 break;
951 else if (matches[i][pos] == matches[0][pos])
952 match_matches++;
953 }
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000954 if (match_matches == num_matches &&
955 (i == num_matches || matches[i] != 0)) {
Chris Allegrettaec58a992000-11-05 21:54:23 +0000956 /* All the matches have the same character at pos+1,
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000957 so paste it into buf... */
Chris Allegretta75864952000-11-05 22:48:35 +0000958 buf = nrealloc(buf, strlen(buf) + 2);
Chris Allegretta442f2c52000-11-14 17:46:06 +0000959 strncat(buf, matches[0] + pos, 1);
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000960 *newplace += 1;
Chris Allegrettaec58a992000-11-05 21:54:23 +0000961 pos++;
Chris Allegretta75864952000-11-05 22:48:35 +0000962 } else {
Chris Allegrettaec58a992000-11-05 21:54:23 +0000963 beep();
964 break;
965 }
966 }
Chris Allegrettae118acc2000-11-06 05:40:03 +0000967 break;
Chris Allegrettaec58a992000-11-05 21:54:23 +0000968 }
Chris Allegretta04d848e2000-11-05 17:54:41 +0000969 } else {
970 /* Ok -- the last char was a TAB. Since they
971 * just hit TAB again, print a list of all the
972 * available choices... */
973 if (matches && num_matches > 0) {
Chris Allegretta04d848e2000-11-05 17:54:41 +0000974
975 /* Blank the edit window, and print the matches out there */
976 blank_edit();
977 wmove(edit, 0, 0);
978
Chris Allegrettaec58a992000-11-05 21:54:23 +0000979 editline = 0;
Chris Allegretta2c975222000-11-15 01:25:42 +0000980
Chris Allegrettaec58a992000-11-05 21:54:23 +0000981 /* Figure out the length of the longest filename */
982 for (i = 0; i < num_matches; i++)
983 if (strlen(matches[i]) > longestname)
984 longestname = strlen(matches[i]);
985
986 if (longestname > COLS - 1)
987 longestname = COLS - 1;
988
Chris Allegretta3b0d1442000-11-05 21:56:54 +0000989 foo = nmalloc(longestname + 5);
990
Chris Allegretta04d848e2000-11-05 17:54:41 +0000991 /* Print the list of matches */
992 for (i = 0, col = 0; i < num_matches; i++) {
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000993
Chris Allegrettaec58a992000-11-05 21:54:23 +0000994 /* make each filename shown be the same length as the longest
Chris Allegrettab5b89ae2000-11-14 18:25:26 +0000995 filename, with two spaces at the end */
Chris Allegrettaec58a992000-11-05 21:54:23 +0000996 snprintf(foo, longestname + 1, matches[i]);
997 while (strlen(foo) < longestname)
998 strcat(foo, " ");
999
1000 strcat(foo, " ");
1001
Chris Allegretta442f2c52000-11-14 17:46:06 +00001002 /* Disable el cursor */
1003 curs_set(0);
Chris Allegretta75864952000-11-05 22:48:35 +00001004 /* now, put the match on the screen */
1005 waddnstr(edit, foo, strlen(foo));
1006 col += strlen(foo);
1007
1008 /* And if the next match isn't going to fit on the
1009 line, move to the next one */
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001010 if (col > (COLS - longestname) && matches[i + 1] != NULL) {
Chris Allegrettaec58a992000-11-05 21:54:23 +00001011 editline++;
1012 wmove(edit, editline, 0);
Chris Allegrettab5b89ae2000-11-14 18:25:26 +00001013 if (editline == editwinrows - 1) {
1014 waddstr(edit, _("(more)"));
1015 break;
1016 }
Chris Allegretta04d848e2000-11-05 17:54:41 +00001017 col = 0;
1018 }
1019 }
Chris Allegretta3b0d1442000-11-05 21:56:54 +00001020 free(foo);
Chris Allegretta04d848e2000-11-05 17:54:41 +00001021 wrefresh(edit);
Chris Allegretta24dd8d62000-11-06 05:45:48 +00001022 } else
1023 beep();
Chris Allegretta04d848e2000-11-05 17:54:41 +00001024
1025 }
1026
1027 edit_refresh();
Chris Allegretta442f2c52000-11-14 17:46:06 +00001028 curs_set(1);
1029 return buf;
Chris Allegretta04d848e2000-11-05 17:54:41 +00001030}
Chris Allegrettabe77c612000-11-24 14:00:16 +00001031#endif