~ubuntu-branches/debian/lenny/nano/lenny

« back to all changes in this revision

Viewing changes to src/files.c

  • Committer: Bazaar Package Importer
  • Author(s): Jordi Mallach
  • Date: 2005-10-26 13:39:02 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20051026133902-un75r2raiz5qff2c
Tags: 1.3.9-1
* The "I fear I'll freeze in Montréal" release.
* New upstream development release.
  - includes Yavor Doganov's new Bulgarian translation (closes: #324385).
* Remove obsolete patches: 01_clear_replace and 02_64bit_line_num.
* debian/control:
  - add "XC-Package-Type: udeb" to nano-udeb, and build nano-udeb
    in a more debhelper-standard way.
  - bump build-deps to debhelper (>= 4.2.0) for udeb support.
  - bump Standards-Version to 3.6.2.0, gratis.
* debian/rules:
  - get rid of ugly hacks for udeb generation, debhelper will take care.
  - major cleanups.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: files.c,v 1.210 2005/06/28 17:35:20 dolorous Exp $ */
 
1
/* $Id: files.c,v 1.247 2005/08/29 19:11:26 dolorous Exp $ */
2
2
/**************************************************************************
3
3
 *   files.c                                                              *
4
4
 *                                                                        *
24
24
#include <config.h>
25
25
#endif
26
26
 
27
 
#include <stdlib.h>
28
27
#include <string.h>
29
28
#include <stdio.h>
30
29
#include <unistd.h>
34
33
#include <errno.h>
35
34
#include <ctype.h>
36
35
#include <pwd.h>
37
 
#include <assert.h>
38
36
#include "proto.h"
39
37
 
40
 
static file_format fmt = NIX_FILE;
41
 
        /* The format of the current file. */
42
 
 
43
 
/* What happens when there is no file to open? aiee! */
44
 
void new_file(void)
45
 
{
46
 
    fileage = make_new_node(NULL);
47
 
    fileage->data = mallocstrcpy(NULL, "");
48
 
    filebot = fileage;
49
 
    edittop = fileage;
50
 
    current = fileage;
51
 
    current_x = 0;
52
 
    totlines = 1;
53
 
    totsize = 0;
54
 
 
55
 
#ifdef ENABLE_COLOR
56
 
    update_color();
57
 
    if (!ISSET(NO_COLOR_SYNTAX))
58
 
        edit_refresh();
59
 
#endif
60
 
}
 
38
/* Add an entry to the openfile openfilestruct.  This should only be
 
39
 * called from open_buffer(). */
 
40
void make_new_buffer(void)
 
41
{
 
42
    /* If there are no entries in openfile, make the first one and
 
43
     * move to it. */
 
44
    if (openfile == NULL) {
 
45
        openfile = make_new_opennode();
 
46
        splice_opennode(openfile, openfile, openfile);
 
47
    /* Otherwise, make a new entry for openfile, splice it in after
 
48
     * the current entry, and move to it. */
 
49
    } else {
 
50
        splice_opennode(openfile, make_new_opennode(), openfile->next);
 
51
        openfile = openfile->next;
 
52
    }
 
53
 
 
54
    /* Initialize the new buffer. */
 
55
    initialize_buffer();
 
56
}
 
57
 
 
58
/* Initialize the current entry of the openfile openfilestruct. */
 
59
void initialize_buffer(void)
 
60
{
 
61
    assert(openfile != NULL);
 
62
 
 
63
    openfile->filename = mallocstrcpy(NULL, "");
 
64
 
 
65
    initialize_buffer_text();
 
66
 
 
67
    openfile->current_x = 0;
 
68
    openfile->placewewant = 0;
 
69
    openfile->current_y = 0;
 
70
 
 
71
    openfile->modified = FALSE;
 
72
#ifndef NANO_SMALL
 
73
    openfile->mark_set = FALSE;
 
74
 
 
75
    openfile->mark_begin = NULL;
 
76
    openfile->mark_begin_x = 0;
 
77
 
 
78
    openfile->fmt = NIX_FILE;
 
79
 
 
80
    openfile->current_stat = NULL;
 
81
#endif
 
82
#ifdef ENABLE_COLOR
 
83
    openfile->colorstrings = NULL;
 
84
#endif
 
85
}
 
86
 
 
87
/* Initialize the text of the current entry of the openfile
 
88
 * openfilestruct. */
 
89
void initialize_buffer_text(void)
 
90
{
 
91
    assert(openfile != NULL);
 
92
 
 
93
    openfile->fileage = make_new_node(NULL);
 
94
    openfile->fileage->data = mallocstrcpy(NULL, "");
 
95
 
 
96
    openfile->filebot = openfile->fileage;
 
97
    openfile->edittop = openfile->fileage;
 
98
    openfile->current = openfile->fileage;
 
99
 
 
100
    openfile->totsize = 0;
 
101
}
 
102
 
 
103
/* If it's not "", filename is a file to open.  We make a new buffer, if
 
104
 * necessary, and then open and read the file, if applicable. */
 
105
void open_buffer(const char *filename)
 
106
{
 
107
    bool new_buffer = (openfile == NULL
 
108
#ifdef ENABLE_MULTIBUFFER
 
109
         || ISSET(MULTIBUFFER)
 
110
#endif
 
111
        );
 
112
        /* Whether we load into this buffer or a new one. */
 
113
    FILE *f;
 
114
    int rc;
 
115
        /* rc == -2 means that we have a new file.  -1 means that the
 
116
         * open() failed.  0 means that the open() succeeded. */
 
117
 
 
118
    assert(filename != NULL);
 
119
 
 
120
#ifndef DISABLE_OPERATINGDIR
 
121
    if (check_operating_dir(filename, FALSE)) {
 
122
        statusbar(_("Can't insert file from outside of %s"),
 
123
                operating_dir);
 
124
        return;
 
125
    }
 
126
#endif
 
127
 
 
128
    /* If the filename isn't blank, open the file.  Otherwise, treat it
 
129
     * as a new file. */
 
130
    rc = (filename[0] != '\0') ? open_file(filename, new_buffer, &f) :
 
131
        -2;
 
132
 
 
133
    /* If we're loading into a new buffer, add a new entry to
 
134
     * openfile. */
 
135
    if (new_buffer)
 
136
        make_new_buffer();
 
137
 
 
138
    /* If we have a file and we're loading into a new buffer, update the
 
139
     * filename. */
 
140
    if (rc != -1 && new_buffer)
 
141
        openfile->filename = mallocstrcpy(openfile->filename, filename);
 
142
 
 
143
    /* If we have a non-new file, read it in.  Then, if the buffer has
 
144
     * no stat, update the stat, if applicable. */
 
145
    if (rc == 0) {
 
146
        read_file(f, filename);
 
147
#ifndef NANO_SMALL
 
148
        if (openfile->current_stat == NULL) {
 
149
            openfile->current_stat =
 
150
                (struct stat *)nmalloc(sizeof(struct stat));
 
151
            stat(filename, openfile->current_stat);
 
152
        }
 
153
#endif
 
154
    }
 
155
 
 
156
    /* If we have a file and we're loading into a new buffer, move back
 
157
     * to the first line of the buffer. */
 
158
    if (rc != -1 && new_buffer)
 
159
        openfile->current = openfile->fileage;
 
160
 
 
161
#ifdef ENABLE_COLOR
 
162
    /* If we're loading into a new buffer, update the colors to account
 
163
     * for it, if applicable. */
 
164
    if (new_buffer)
 
165
        color_update();
 
166
#endif
 
167
}
 
168
 
 
169
/* Update the screen to account for the current buffer. */
 
170
void display_buffer(void)
 
171
{
 
172
    /* Update the titlebar, since the filename may have changed. */
 
173
    titlebar(NULL);
 
174
 
 
175
#ifdef ENABLE_COLOR
 
176
    /* Make sure we're using the buffer's associated colors, if
 
177
     * applicable. */
 
178
    color_init();
 
179
#endif
 
180
 
 
181
    /* Update the edit window. */
 
182
    edit_refresh();
 
183
}
 
184
 
 
185
#ifdef ENABLE_MULTIBUFFER
 
186
/* Switch to the next file buffer if next_buf is TRUE.  Otherwise,
 
187
 * switch to the previous file buffer. */
 
188
void switch_to_prevnext_buffer(bool next_buf)
 
189
{
 
190
    assert(openfile != NULL);
 
191
 
 
192
    /* If only one file buffer is open, indicate it on the statusbar and
 
193
     * get out. */
 
194
    if (openfile == openfile->next) {
 
195
        statusbar(_("No more open file buffers"));
 
196
        return;
 
197
    }
 
198
 
 
199
    /* Switch to the next or previous file buffer, depending on the
 
200
     * value of next_buf. */
 
201
    openfile = next_buf ? openfile->next : openfile->prev;
 
202
 
 
203
#ifdef DEBUG
 
204
    fprintf(stderr, "filename is %s\n", openfile->filename);
 
205
#endif
 
206
 
 
207
    /* Update the screen to account for the current buffer. */
 
208
    display_buffer();
 
209
 
 
210
    /* Indicate the switch on the statusbar. */
 
211
    statusbar(_("Switched to %s"),
 
212
        ((openfile->filename[0] == '\0') ? _("New Buffer") :
 
213
        openfile->filename));
 
214
 
 
215
#ifdef DEBUG
 
216
    dump_filestruct(openfile->current);
 
217
#endif
 
218
}
 
219
 
 
220
/* Switch to the previous entry in the openfile filebuffer. */
 
221
void switch_to_prev_buffer_void(void)
 
222
{
 
223
    switch_to_prevnext_buffer(FALSE);
 
224
}
 
225
 
 
226
/* Switch to the next entry in the openfile filebuffer. */
 
227
void switch_to_next_buffer_void(void)
 
228
{
 
229
    switch_to_prevnext_buffer(TRUE);
 
230
}
 
231
 
 
232
/* Delete an entry from the openfile filebuffer, and switch to the one
 
233
 * after it.  Return TRUE on success, or FALSE if there are no more open
 
234
 * file buffers. */
 
235
bool close_buffer(void)
 
236
{
 
237
    assert(openfile != NULL);
 
238
 
 
239
    /* If only one file buffer is open, get out. */
 
240
    if (openfile == openfile->next)
 
241
        return FALSE;
 
242
 
 
243
    /* Switch to the next file buffer. */
 
244
    switch_to_next_buffer_void();
 
245
 
 
246
    /* Close the file buffer we had open before. */
 
247
    unlink_opennode(openfile->prev);
 
248
 
 
249
    display_main_list();
 
250
 
 
251
    return TRUE;
 
252
}
 
253
#endif /* ENABLE_MULTIBUFFER */
61
254
 
62
255
/* We make a new line of text from buf.  buf is length buf_len.  If
63
256
 * first_line_ins is TRUE, then we put the new line at the top of the
72
265
     * here. */
73
266
    unsunder(buf, buf_len);
74
267
 
75
 
    assert(strlen(buf) == buf_len);
 
268
    assert(openfile->fileage != NULL && strlen(buf) == buf_len);
76
269
 
77
270
    fileptr->data = mallocstrcpy(NULL, buf);
78
271
 
83
276
        fileptr->data[buf_len - 1] = '\0';
84
277
#endif
85
278
 
86
 
    if (*first_line_ins == TRUE || fileage == NULL) {
 
279
    if (*first_line_ins == TRUE) {
87
280
        /* Special case: We're inserting with the cursor on the first
88
281
         * line. */
89
282
        fileptr->prev = NULL;
90
 
        fileptr->next = fileage;
 
283
        fileptr->next = openfile->fileage;
91
284
        fileptr->lineno = 1;
92
285
        if (*first_line_ins == TRUE) {
93
286
            *first_line_ins = FALSE;
94
287
            /* If we're inserting into the first line of the file, then
95
288
             * we want to make sure that our edit buffer stays on the
96
289
             * first line and that fileage stays up to date. */
97
 
            edittop = fileptr;
 
290
            openfile->edittop = fileptr;
98
291
        } else
99
 
            filebot = fileptr;
100
 
        fileage = fileptr;
 
292
            openfile->filebot = fileptr;
 
293
        openfile->fileage = fileptr;
101
294
    } else {
102
295
        assert(prevnode != NULL);
103
296
 
110
303
    return fileptr;
111
304
}
112
305
 
113
 
/* Load a file into the edit buffer.  This takes data from the file
114
 
 * struct. */
115
 
void load_file(void)
116
 
{
117
 
    current = fileage;
118
 
 
119
 
#ifdef ENABLE_MULTIBUFFER
120
 
    /* Add a new entry to the open_files structure. */
121
 
    add_open_file(FALSE);
122
 
 
123
 
    /* Reinitialize the shortcut list. */
124
 
    shortcut_init(FALSE);
125
 
#endif
126
 
}
127
 
 
128
306
void read_file(FILE *f, const char *filename)
129
307
{
130
308
    size_t num_lines = 0;
131
309
        /* The number of lines in the file. */
132
 
    size_t num_chars;
133
 
        /* The number of characters in the file. */
134
310
    size_t len = 0;
135
311
        /* The length of the current line of the file. */
136
312
    size_t i = 0;
141
317
        /* The current input character. */
142
318
    char *buf;
143
319
        /* The buffer where we store chunks of the file. */
144
 
    filestruct *fileptr = current;
 
320
    filestruct *fileptr = openfile->current;
145
321
        /* The current line of the file. */
146
322
    bool first_line_ins = FALSE;
147
323
        /* Whether we're inserting with the cursor on the first line. */
153
329
        /* 0 = *nix, 1 = DOS, 2 = Mac, 3 = both DOS and Mac. */
154
330
#endif
155
331
 
 
332
    assert(openfile->fileage != NULL && openfile->current != NULL);
 
333
 
156
334
    buf = charalloc(bufx);
157
335
    buf[0] = '\0';
158
336
 
159
 
    if (current != NULL) {
160
 
        if (current == fileage)
161
 
            first_line_ins = TRUE;
162
 
        else
163
 
            fileptr = current->prev;
164
 
    }
165
 
 
166
 
    /* For the assertion in read_line(), it must be true that if current
167
 
     * is NULL, then so is fileage. */
168
 
    assert(current != NULL || fileage == NULL);
169
 
 
170
 
#ifndef NANO_SMALL
171
 
    /* We don't know which file format we have yet, so assume it's a
172
 
     * *nix file for now. */
173
 
    fmt = NIX_FILE;
174
 
#endif
175
 
 
176
 
    /* Read the entire file into the file struct. */
 
337
    if (openfile->current == openfile->fileage)
 
338
        first_line_ins = TRUE;
 
339
    else
 
340
        fileptr = openfile->current->prev;
 
341
 
 
342
    /* Read the entire file into the filestruct. */
177
343
    while ((input_int = getc(f)) != EOF) {
178
344
        input = (char)input_int;
179
345
 
203
369
        /* If it's a Mac file ('\r' without '\n'), and file conversion
204
370
         * isn't disabled, handle it! */
205
371
        } else if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r') {
206
 
 
207
372
            /* If we currently think the file is a *nix file, set format
208
373
             * to Mac.  If we currently think the file is a DOS file,
209
374
             * set format to both DOS and Mac. */
279
444
 
280
445
    free(buf);
281
446
 
282
 
    /* If we didn't get a file and we don't already have one, make a new
283
 
     * file. */
 
447
    /* If we didn't get a file and we don't already have one, open a
 
448
     * blank buffer. */
284
449
    if (fileptr == NULL)
285
 
        new_file();
 
450
        open_buffer("");
286
451
 
287
 
    /* Did we try to insert a file of 0 bytes? */
 
452
    /* Did we try to insert a file of zero bytes? */
288
453
    if (num_lines != 0) {
289
 
        if (current != NULL) {
290
 
            fileptr->next = current;
291
 
            current->prev = fileptr;
292
 
            renumber(current);
293
 
            current_x = 0;
294
 
            placewewant = 0;
 
454
        if (openfile->current != NULL) {
 
455
            fileptr->next = openfile->current;
 
456
            openfile->current->prev = fileptr;
 
457
            renumber(openfile->current);
 
458
            openfile->current_x = 0;
 
459
            openfile->placewewant = 0;
295
460
        } else if (fileptr->next == NULL) {
296
 
            filebot = fileptr;
 
461
            openfile->filebot = fileptr;
297
462
            new_magicline();
298
 
            totsize--;
 
463
            openfile->totsize--;
299
464
        }
300
465
    }
301
466
 
302
 
    get_totals(fileage, filebot, NULL, &num_chars);
303
 
    totsize += num_chars;
 
467
    openfile->totsize += get_totsize(openfile->fileage,
 
468
        openfile->filebot);
304
469
 
305
470
#ifndef NANO_SMALL
306
471
    if (format == 3)
309
474
                "Read %lu lines (Converted from DOS and Mac format)",
310
475
                (unsigned long)num_lines), (unsigned long)num_lines);
311
476
    else if (format == 2) {
312
 
        fmt = MAC_FILE;
 
477
        openfile->fmt = MAC_FILE;
313
478
        statusbar(P_("Read %lu line (Converted from Mac format)",
314
479
                "Read %lu lines (Converted from Mac format)",
315
480
                (unsigned long)num_lines), (unsigned long)num_lines);
316
481
    } else if (format == 1) {
317
 
        fmt = DOS_FILE;
 
482
        openfile->fmt = DOS_FILE;
318
483
        statusbar(P_("Read %lu line (Converted from DOS format)",
319
484
                "Read %lu lines (Converted from DOS format)",
320
485
                (unsigned long)num_lines), (unsigned long)num_lines);
322
487
#endif
323
488
        statusbar(P_("Read %lu line", "Read %lu lines",
324
489
                (unsigned long)num_lines), (unsigned long)num_lines);
325
 
 
326
 
    totlines += num_lines;
327
490
}
328
491
 
329
492
/* Open the file (and decide if it exists).  If newfie is TRUE, display
338
501
    int fd;
339
502
    struct stat fileinfo;
340
503
 
341
 
    assert(f != NULL);
 
504
    assert(filename != NULL && f != NULL);
342
505
 
343
 
    if (filename == NULL || filename[0] == '\0' ||
344
 
            stat(filename, &fileinfo) == -1) {
 
506
    if (stat(filename, &fileinfo) == -1) {
345
507
        if (newfie) {
346
508
            statusbar(_("New File"));
347
509
            return -2;
349
511
        statusbar(_("\"%s\" not found"), filename);
350
512
        return -1;
351
513
    } else if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
352
 
                S_ISBLK(fileinfo.st_mode)) {
 
514
        S_ISBLK(fileinfo.st_mode)) {
353
515
        /* Don't open character or block files.  Sorry, /dev/sndstat! */
354
 
        statusbar(S_ISDIR(fileinfo.st_mode) ? _("\"%s\" is a directory")
355
 
                : _("File \"%s\" is a device file"), filename);
 
516
        statusbar(S_ISDIR(fileinfo.st_mode) ?
 
517
                _("\"%s\" is a directory") :
 
518
                _("File \"%s\" is a device file"), filename);
356
519
        return -1;
357
520
    } else if ((fd = open(filename, O_RDONLY)) == -1) {
358
521
        statusbar(_("Error reading %s: %s"), filename, strerror(errno));
369
532
        } else
370
533
            statusbar(_("Reading File"));
371
534
    }
 
535
 
372
536
    return 0;
373
537
}
374
538
 
409
573
    return buf;
410
574
}
411
575
 
412
 
#ifndef NANO_SMALL
413
 
void execute_command(const char *command)
414
 
{
415
 
#ifdef ENABLE_MULTIBUFFER
416
 
    if (ISSET(MULTIBUFFER)) {
417
 
        /* Update the current entry in the open_files structure. */
418
 
        add_open_file(TRUE);
419
 
        new_file();
420
 
        UNSET(MODIFIED);
421
 
        UNSET(MARK_ISSET);
422
 
    }
423
 
#endif /* ENABLE_MULTIBUFFER */
424
 
    open_pipe(command);
425
 
#ifdef ENABLE_MULTIBUFFER
426
 
    /* Add this new entry to the open_files structure. */
427
 
    if (ISSET(MULTIBUFFER))
428
 
        load_file();
429
 
#endif /* ENABLE_MULTIBUFFER */
430
 
}
431
 
#endif /* !NANO_SMALL */
432
 
 
433
 
/* name is a file name to open.  We make a new buffer if necessary, then
434
 
 * open and read the file. */
435
 
void load_buffer(const char *name)
436
 
{
437
 
    bool new_buffer = (fileage == NULL
438
 
#ifdef ENABLE_MULTIBUFFER
439
 
         || ISSET(MULTIBUFFER)
440
 
#endif
441
 
        );
442
 
        /* new_buffer says whether we load into this buffer or a new
443
 
         * one.  If new_buffer is TRUE, we display "New File" if the
444
 
         * file is not found, and if it is found we set filename and add
445
 
         * a new open_files entry. */
446
 
    FILE *f;
447
 
    int rc;
448
 
        /* rc == -2 means that the statusbar displayed "New File".  -1
449
 
         * means that the open failed.  0 means success. */
450
 
 
451
 
#ifndef DISABLE_OPERATINGDIR
452
 
    if (check_operating_dir(name, FALSE)) {
453
 
        statusbar(_("Can't insert file from outside of %s"),
454
 
                operating_dir);
455
 
        return;
456
 
    }
457
 
#endif
458
 
 
459
 
#ifdef ENABLE_MULTIBUFFER
460
 
    /* Update the current entry in the open_files structure. */
461
 
    add_open_file(TRUE);
462
 
#endif
463
 
 
464
 
    rc = open_file(name, new_buffer, &f);
465
 
 
466
 
#ifdef ENABLE_MULTIBUFFER
467
 
    if (rc != -1 && ISSET(MULTIBUFFER)) {
468
 
        UNSET(MODIFIED);
469
 
#ifndef NANO_SMALL
470
 
        UNSET(MARK_ISSET);
471
 
#endif
472
 
    }
473
 
#endif
474
 
 
475
 
    if (rc != -1 && new_buffer) {
476
 
        filename = mallocstrcpy(filename, name);
477
 
        new_file();
478
 
    }
479
 
 
480
 
    if (rc == 0) {
481
 
        file_format fmt_save = fmt;
482
 
 
483
 
        read_file(f, filename);
484
 
 
485
 
        /* If we're not loading into a new buffer, preserve the file
486
 
         * format. */
487
 
        if (!new_buffer)
488
 
            fmt = fmt_save;
489
 
 
490
 
#ifndef NANO_SMALL
491
 
        stat(filename, &originalfilestat);
492
 
#endif
493
 
    }
494
 
 
495
 
    /* Add this new entry to the open_files structure if we have
496
 
     * multibuffer support, or to the main filestruct if we don't. */
497
 
    if (rc != -1 && new_buffer)
498
 
        load_file();
499
 
}
500
 
 
501
576
void do_insertfile(
502
577
#ifndef NANO_SMALL
503
578
        bool execute
510
585
    const char *msg;
511
586
    char *ans = mallocstrcpy(NULL, "");
512
587
        /* The last answer the user typed on the statusbar. */
513
 
    filestruct *edittop_save = edittop;
514
 
    ssize_t current_y_save = current_y;
 
588
    filestruct *edittop_save = openfile->edittop;
 
589
    ssize_t current_y_save = openfile->current_y;
515
590
    bool at_edittop = FALSE;
516
591
        /* Whether we're at the top of the edit window. */
517
592
 
522
597
    while (TRUE) {
523
598
#ifndef NANO_SMALL
524
599
        if (execute) {
 
600
            msg = 
525
601
#ifdef ENABLE_MULTIBUFFER
526
 
            if (ISSET(MULTIBUFFER))
527
 
                msg = N_("Command to execute in new buffer [from %s] ");
528
 
            else
 
602
                ISSET(MULTIBUFFER) ? 
 
603
                N_("Command to execute in new buffer [from %s] ") :
529
604
#endif
530
 
                msg = N_("Command to execute [from %s] ");
 
605
                N_("Command to execute [from %s] ");
531
606
        } else {
532
607
#endif
 
608
            msg =
533
609
#ifdef ENABLE_MULTIBUFFER
534
 
            if (ISSET(MULTIBUFFER)) {
535
 
                msg = N_("File to insert into new buffer [from %s] ");
536
 
            } else
 
610
                ISSET(MULTIBUFFER) ? 
 
611
                N_("File to insert into new buffer [from %s] ") :
537
612
#endif
538
 
                msg = N_("File to insert [from %s] ");
 
613
                N_("File to insert [from %s] ");
539
614
#ifndef NANO_SMALL
540
615
        }
541
616
#endif
565
640
            statusbar(_("Cancelled"));
566
641
            break;
567
642
        } else {
568
 
            size_t pww_save = placewewant;
 
643
            size_t pww_save = openfile->placewewant;
569
644
 
570
645
            ans = mallocstrcpy(ans, answer);
571
646
 
621
696
                 * looks like a new buffer, and keep track of whether
622
697
                 * the top of the partition is the top of the edit
623
698
                 * window. */
624
 
                filepart = partition_filestruct(current, current_x,
625
 
                        current, current_x);
626
 
                at_edittop = (fileage == edittop);
 
699
                filepart = partition_filestruct(openfile->current,
 
700
                        openfile->current_x, openfile->current,
 
701
                        openfile->current_x);
 
702
                at_edittop =
 
703
                        (openfile->fileage == openfile->edittop);
627
704
#ifdef ENABLE_MULTIBUFFER
628
705
            }
629
706
#endif
630
707
 
631
708
#ifndef NANO_SMALL
632
 
            if (execute)
 
709
            if (execute) {
 
710
#ifdef ENABLE_MULTIBUFFER
 
711
                if (ISSET(MULTIBUFFER))
 
712
                    /* Open a blank buffer. */
 
713
                    open_buffer("");
 
714
#endif
 
715
 
 
716
                /* Save the command's output in the current buffer. */
633
717
                execute_command(answer);
634
 
            else {
 
718
            } else {
635
719
#endif
 
720
                /* Make sure the path to the file specified in answer is
 
721
                 * tilde-expanded. */
636
722
                answer = mallocstrassn(answer,
637
723
                        real_dir_from_tilde(answer));
638
 
                load_buffer(answer);
 
724
 
 
725
                /* Save the file specified in answer in the current
 
726
                 * buffer. */
 
727
                open_buffer(answer);
639
728
#ifndef NANO_SMALL
640
729
            }
641
730
#endif
642
731
 
643
732
#ifdef ENABLE_MULTIBUFFER
644
 
            if (!ISSET(MULTIBUFFER))
 
733
            if (ISSET(MULTIBUFFER))
 
734
                /* Update the screen to account for the current
 
735
                 * buffer. */
 
736
                display_buffer();
 
737
            else
645
738
#endif
646
739
            {
647
 
                filestruct *top_save = fileage;
 
740
                filestruct *top_save = openfile->fileage;
648
741
 
649
742
                /* If we didn't insert into a new buffer, and we were at
650
743
                 * the top of the edit window before, set the saved
652
745
                 * and update the current y-coordinate to account for
653
746
                 * the number of lines inserted. */
654
747
                if (at_edittop)
655
 
                    edittop_save = fileage;
656
 
                current_y += current_y_save;
 
748
                    edittop_save = openfile->fileage;
 
749
                openfile->current_y += current_y_save;
657
750
 
658
751
                /* If we didn't insert into a new buffer, unpartition
659
752
                 * the filestruct so that it contains all the text
666
759
                 * partition. */
667
760
                renumber(top_save);
668
761
 
669
 
                /* Set edittop back to what it was before. */
670
 
                edittop = edittop_save;
671
 
            }
672
 
 
673
 
#ifdef ENABLE_MULTIBUFFER
674
 
            if (ISSET(MULTIBUFFER)) {
675
 
                /* Update the titlebar. */
676
 
                titlebar(NULL);
677
 
 
678
 
                /* Reinitialize the shortcut list. */
679
 
                shortcut_init(FALSE);
680
 
            } else {
681
 
#endif
 
762
                /* Restore the old edittop. */
 
763
                openfile->edittop = edittop_save;
 
764
 
 
765
                /* Restore the old place we want. */
 
766
                openfile->placewewant = pww_save;
 
767
 
682
768
                /* Mark the file as modified. */
683
769
                set_modified();
684
770
 
685
 
                /* Restore the old place we want. */
686
 
                placewewant = pww_save;
687
 
#ifdef ENABLE_MULTIBUFFER
 
771
                /* Update the screen. */
 
772
                edit_refresh();
688
773
            }
689
 
#endif
690
 
 
691
 
            /* Refresh the screen. */
692
 
            edit_refresh();
693
774
 
694
775
            break;
695
776
        }
714
795
    display_main_list();
715
796
}
716
797
 
717
 
#ifdef ENABLE_MULTIBUFFER
718
 
/* Create a new openfilestruct node. */
719
 
openfilestruct *make_new_opennode(void)
720
 
{
721
 
    openfilestruct *newnode =
722
 
        (openfilestruct *)nmalloc(sizeof(openfilestruct));
723
 
    newnode->filename = NULL;
724
 
 
725
 
    return newnode;
726
 
}
727
 
 
728
 
/* Splice a node into an existing openfilestruct. */
729
 
void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
730
 
        openfilestruct *end)
731
 
{
732
 
    assert(newnode != NULL && begin != NULL);
733
 
 
734
 
    newnode->next = end;
735
 
    newnode->prev = begin;
736
 
    begin->next = newnode;
737
 
    if (end != NULL)
738
 
        end->prev = newnode;
739
 
}
740
 
 
741
 
/* Unlink a node from the rest of the openfilestruct, and delete it. */
742
 
void unlink_opennode(openfilestruct *fileptr)
743
 
{
744
 
    assert(fileptr != NULL && fileptr->prev != NULL && fileptr->next != NULL && fileptr != fileptr->prev && fileptr != fileptr->next);
745
 
 
746
 
    fileptr->prev->next = fileptr->next;
747
 
    fileptr->next->prev = fileptr->prev;
748
 
    delete_opennode(fileptr);
749
 
}
750
 
 
751
 
/* Delete a node from the openfilestruct. */
752
 
void delete_opennode(openfilestruct *fileptr)
753
 
{
754
 
    assert(fileptr != NULL && fileptr->filename != NULL && fileptr->fileage != NULL);
755
 
 
756
 
    free(fileptr->filename);
757
 
    free_filestruct(fileptr->fileage);
758
 
    free(fileptr);
759
 
}
760
 
 
761
 
#ifdef DEBUG
762
 
/* Deallocate all memory associated with this and later files, including
763
 
 * the lines of text. */
764
 
void free_openfilestruct(openfilestruct *src)
765
 
{
766
 
    assert(src != NULL);
767
 
 
768
 
    while (src != src->next) {
769
 
        src = src->next;
770
 
        delete_opennode(src->prev);
771
 
    }
772
 
    delete_opennode(src);
773
 
}
774
 
#endif
775
 
 
776
 
/* Add/update an entry to the open_files openfilestruct.  If update is
777
 
 * FALSE, a new entry is created; otherwise, the current entry is
778
 
 * updated. */
779
 
void add_open_file(bool update)
780
 
{
781
 
    if (update && open_files == NULL)
782
 
        return;
783
 
 
784
 
    /* If there are no entries in open_files, make the first one. */
785
 
    if (open_files == NULL) {
786
 
        open_files = make_new_opennode();
787
 
        splice_opennode(open_files, open_files, open_files);
788
 
    /* Otherwise, if we're not updating, make a new entry for
789
 
     * open_files and splice it in after the current entry. */
790
 
    } else if (!update) {
791
 
        splice_opennode(open_files, make_new_opennode(),
792
 
                open_files->next);
793
 
        open_files = open_files->next;
794
 
    }
795
 
 
796
 
    /* Save the current filename. */
797
 
    open_files->filename = mallocstrcpy(open_files->filename, filename);
798
 
 
799
 
#ifndef NANO_SMALL
800
 
    /* Save the current file's stat. */
801
 
    open_files->originalfilestat = originalfilestat;
802
 
#endif
803
 
 
804
 
    /* Save the current file buffer. */
805
 
    open_files->fileage = fileage;
806
 
    open_files->filebot = filebot;
807
 
 
808
 
    /* Save the current top of the edit window. */
809
 
    open_files->edittop = edittop;
810
 
 
811
 
    /* Save the current line. */
812
 
    open_files->current = current;
813
 
 
814
 
    /* Save the current cursor position. */
815
 
    open_files->current_x = current_x;
816
 
 
817
 
    /* Save the current place we want. */
818
 
    open_files->placewewant = placewewant;
819
 
 
820
 
    /* Save the current total number of lines. */
821
 
    open_files->totlines = totlines;
822
 
 
823
 
    /* Save the current total size. */
824
 
    open_files->totsize = totsize;
825
 
 
826
 
    /* Start with no flags saved. */
827
 
    open_files->flags = 0;
828
 
 
829
 
    /* Save the current modification status. */
830
 
    if (ISSET(MODIFIED))
831
 
        open_files->flags |= MODIFIED;
832
 
 
833
 
#ifndef NANO_SMALL
834
 
    /* Save the current marking status and mark, if applicable. */
835
 
    if (ISSET(MARK_ISSET)) {
836
 
        open_files->flags |= MARK_ISSET;
837
 
        open_files->mark_beginbuf = mark_beginbuf;
838
 
        open_files->mark_beginx = mark_beginx;
839
 
    }
840
 
 
841
 
    /* Save the current file format. */
842
 
    open_files->fmt = fmt;
843
 
#endif
844
 
 
845
 
#ifdef DEBUG
846
 
    fprintf(stderr, "filename is %s\n", open_files->filename);
847
 
#endif
848
 
}
849
 
 
850
 
/* Read the current entry in the open_files structure and set up the
851
 
 * currently open file buffer using that entry's information. */
852
 
void load_open_file(void)
853
 
{
854
 
    assert(open_files != NULL);
855
 
 
856
 
    /* Restore the current filename. */
857
 
    filename = mallocstrcpy(filename, open_files->filename);
858
 
 
859
 
#ifndef NANO_SMALL
860
 
    /* Restore the current file's stat. */
861
 
    originalfilestat = open_files->originalfilestat;
862
 
#endif
863
 
 
864
 
    /* Restore the current file buffer. */
865
 
    fileage = open_files->fileage;
866
 
    filebot = open_files->filebot;
867
 
 
868
 
    /* Restore the current top of the edit window. */
869
 
    edittop = open_files->edittop;
870
 
 
871
 
    /* Restore the current line. */
872
 
    current = open_files->current;
873
 
 
874
 
    /* Restore the current cursor position. */
875
 
    current_x = open_files->current_x;
876
 
 
877
 
    /* Restore the current place we want. */
878
 
    placewewant = open_files->placewewant;
879
 
 
880
 
    /* Restore the current total number of lines. */
881
 
    totlines = open_files->totlines;
882
 
 
883
 
    /* Restore the current total size. */
884
 
    totsize = open_files->totsize;
885
 
 
886
 
    /* Restore the current modification status. */
887
 
    if (open_files->flags & MODIFIED)
888
 
        SET(MODIFIED);
889
 
    else
890
 
        UNSET(MODIFIED);
891
 
 
892
 
#ifndef NANO_SMALL
893
 
    /* Restore the current marking status and mark, if applicable. */
894
 
    if (open_files->flags & MARK_ISSET) {
895
 
        mark_beginbuf = open_files->mark_beginbuf;
896
 
        mark_beginx = open_files->mark_beginx;
897
 
        SET(MARK_ISSET);
898
 
    } else
899
 
        UNSET(MARK_ISSET);
900
 
 
901
 
    /* Restore the current file format. */
902
 
    fmt = open_files->fmt;
903
 
#endif
904
 
 
905
 
#ifdef ENABLE_COLOR
906
 
    update_color();
907
 
#endif
908
 
    edit_refresh();
909
 
 
910
 
    /* Update the titlebar. */
911
 
    titlebar(NULL);
912
 
}
913
 
 
914
 
/* Open either the next or previous file buffer. */
915
 
void open_prevnext_file(bool next_file)
916
 
{
917
 
    assert(open_files != NULL);
918
 
 
919
 
    add_open_file(TRUE);
920
 
 
921
 
    /* If only one file buffer is open, indicate it on the statusbar and
922
 
     * get out. */
923
 
    if (open_files == open_files->next) {
924
 
        statusbar(_("No more open file buffers"));
925
 
        return;
926
 
    }
927
 
 
928
 
    /* Switch to the next or previous file, depending on the value of
929
 
     * next. */
930
 
    open_files = next_file ? open_files->next : open_files->prev;
931
 
 
932
 
#ifdef DEBUG
933
 
    fprintf(stderr, "filename is %s\n", open_files->filename);
934
 
#endif
935
 
 
936
 
    /* Load the file we switched to. */
937
 
    load_open_file();
938
 
 
939
 
    /* And indicate the switch on the statusbar. */
940
 
    statusbar(_("Switched to %s"),
941
 
      ((open_files->filename[0] == '\0') ? _("New Buffer") :
942
 
        open_files->filename));
943
 
 
944
 
#ifdef DEBUG
945
 
    dump_buffer(current);
946
 
#endif
947
 
}
948
 
 
949
 
/* Open the previous entry in the open_files structure.  This function
950
 
 * is used by the shortcut list. */
951
 
void open_prevfile_void(void)
952
 
{
953
 
    open_prevnext_file(FALSE);
954
 
}
955
 
 
956
 
/* Open the next entry in the open_files structure.  This function is
957
 
 * used by the shortcut list. */
958
 
void open_nextfile_void(void)
959
 
{
960
 
    open_prevnext_file(TRUE);
961
 
}
962
 
 
963
 
/* Delete an entry from the open_files filestruct.  After deletion of an
964
 
 * entry, the next entry is opened.  Return TRUE on success or FALSE if
965
 
 * there are no more open file buffers. */
966
 
bool close_open_file(void)
967
 
{
968
 
    assert(open_files != NULL);
969
 
 
970
 
    /* If only one file is open, get out. */
971
 
    if (open_files == open_files->next)
972
 
        return FALSE;
973
 
 
974
 
    /* Open the next file. */
975
 
    open_nextfile_void();
976
 
 
977
 
    /* Close the file we had open before. */
978
 
    unlink_opennode(open_files->prev);
979
 
 
980
 
    /* Reinitialize the shortcut list. */
981
 
    shortcut_init(FALSE);
982
 
    display_main_list();
983
 
 
984
 
    return TRUE;
985
 
}
986
 
#endif /* ENABLE_MULTIBUFFER */
987
 
 
988
798
/* When passed "[relative path]" or "[relative path][filename]" in
989
799
 * origpath, return "[full path]" or "[full path][filename]" on success,
990
800
 * or NULL on error.  Do this if the file doesn't exist but the relative
1243
1053
        whereami2 = strstr(full_operating_dir, fullpath);
1244
1054
 
1245
1055
    /* If both searches failed, we're outside the operating directory.
1246
 
     * Otherwise, check the search results; if the full operating
 
1056
     * Otherwise, check the search results.  If the full operating
1247
1057
     * directory path is not at the beginning of the full current path
1248
1058
     * (for normal usage) and vice versa (for tab completion, if we're
1249
1059
     * allowing it), we're outside the operating directory. */
1281
1091
#endif
1282
1092
 
1283
1093
/* Read from inn, write to out.  We assume inn is opened for reading,
1284
 
 * and out for writing.  We return 0 on success, -1 on read error, -2 on
1285
 
 * write error. */
 
1094
 * and out for writing.  We return 0 on success, -1 on read error, or -2
 
1095
 * on write error. */
1286
1096
int copy_file(FILE *inn, FILE *out)
1287
1097
{
1288
1098
    char buf[BUFSIZ];
1314
1124
/* Write a file out.  If f_open isn't NULL, we assume that it is a
1315
1125
 * stream associated with the file, and we don't try to open it
1316
1126
 * ourselves.  If tmp is TRUE, we set the umask to disallow anyone else
1317
 
 * from accessing the file, we don't set the global variable filename to
1318
 
 * its name, and we don't print out how many lines we wrote on the
1319
 
 * statusbar.
 
1127
 * from accessing the file, we don't set the filename to its name, and
 
1128
 * we don't print out how many lines we wrote on the statusbar.
1320
1129
 *
1321
1130
 * tmp means we are writing a temporary file in a secure fashion.  We
1322
1131
 * use it when spell checking or dumping the file on an error.
1323
1132
 *
1324
 
 * append == 1 means we are appending instead of overwriting.
1325
 
 * append == 2 means we are prepending instead of overwriting.
 
1133
 * append == APPEND means we are appending instead of overwriting.
 
1134
 * append == PREPEND means we are prepending instead of overwriting.
1326
1135
 *
1327
1136
 * nonamechange means don't change the current filename.  It is ignored
1328
1137
 * if tmp is FALSE or if we're appending/prepending.
1329
1138
 *
1330
1139
 * Return 0 on success or -1 on error. */
1331
 
int write_file(const char *name, FILE *f_open, bool tmp, int append,
1332
 
        bool nonamechange)
 
1140
int write_file(const char *name, FILE *f_open, bool tmp, append_type
 
1141
        append, bool nonamechange)
1333
1142
{
1334
1143
    int retval = -1;
1335
1144
        /* Instead of returning in this function, you should always
1336
1145
         * merely set retval and then goto cleanup_and_exit. */
1337
1146
    size_t lineswritten = 0;
1338
 
    const filestruct *fileptr = fileage;
 
1147
    const filestruct *fileptr = openfile->fileage;
1339
1148
    int fd;
1340
1149
        /* The file descriptor we use. */
1341
1150
    mode_t original_umask = 0;
1347
1156
    struct stat st;
1348
1157
        /* The status fields filled in by stat(). */
1349
1158
    bool anyexists;
1350
 
        /* The result of lstat().  Same as realexists unless name is a
1351
 
         * link. */
 
1159
        /* The result of lstat().  The same as realexists, unless name
 
1160
         * is a link. */
1352
1161
    struct stat lst;
1353
1162
        /* The status fields filled in by lstat(). */
1354
1163
    char *realname;
1404
1213
     * aren't appending, prepending, or writing a selection, we backup
1405
1214
     * only if the file has not been modified by someone else since nano
1406
1215
     * opened it. */
1407
 
    if (ISSET(BACKUP_FILE) && !tmp && realexists &&
1408
 
        (append != 0 || ISSET(MARK_ISSET) ||
1409
 
        originalfilestat.st_mtime == st.st_mtime)) {
 
1216
    if (ISSET(BACKUP_FILE) && !tmp && realexists && ((append !=
 
1217
        OVERWRITE || openfile->mark_set) ||
 
1218
        openfile->current_stat->st_mtime == st.st_mtime)) {
1410
1219
        FILE *backup_file;
1411
1220
        char *backupname;
1412
1221
        struct utimbuf filetime;
1413
1222
        int copy_status;
1414
1223
 
1415
1224
        /* Save the original file's access and modification times. */
1416
 
        filetime.actime = originalfilestat.st_atime;
1417
 
        filetime.modtime = originalfilestat.st_mtime;
 
1225
        filetime.actime = openfile->current_stat->st_atime;
 
1226
        filetime.modtime = openfile->current_stat->st_mtime;
1418
1227
 
1419
1228
        if (f_open == NULL) {
1420
1229
            /* Open the original file to copy to the backup. */
1478
1287
         * we write. */
1479
1288
        backup_file = fopen(backupname, "wb");
1480
1289
 
1481
 
        if (backup_file == NULL ||
1482
 
                chmod(backupname, originalfilestat.st_mode) == -1) {
 
1290
        if (backup_file == NULL || chmod(backupname,
 
1291
                openfile->current_stat->st_mode) == -1) {
1483
1292
            statusbar(_("Error writing %s: %s"), backupname,
1484
1293
                strerror(errno));
1485
1294
            free(backupname);
1497
1306
        copy_status = copy_file(f, backup_file);
1498
1307
 
1499
1308
        /* And set metadata. */
1500
 
        if (copy_status != 0 ||
1501
 
                chown(backupname, originalfilestat.st_uid,
1502
 
                originalfilestat.st_gid) == -1 ||
 
1309
        if (copy_status != 0 || chown(backupname,
 
1310
                openfile->current_stat->st_uid,
 
1311
                openfile->current_stat->st_gid) == -1 ||
1503
1312
                utime(backupname, &filetime) == -1) {
1504
1313
            free(backupname);
1505
1314
            if (copy_status == -1)
1536
1345
    }
1537
1346
 
1538
1347
    /* If we're prepending, copy the file to a temp file. */
1539
 
    if (append == 2) {
 
1348
    if (append == PREPEND) {
1540
1349
        int fd_source;
1541
1350
        FILE *f_source = NULL;
1542
1351
 
1576
1385
        /* Now open the file in place.  Use O_EXCL if tmp is TRUE.  This
1577
1386
         * is copied from joe, because wiggy says so *shrug*. */
1578
1387
        fd = open(realname, O_WRONLY | O_CREAT |
1579
 
                ((append == 1) ? O_APPEND : (tmp ? O_EXCL : O_TRUNC)),
1580
 
                S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |
1581
 
                S_IWOTH);
 
1388
                ((append == APPEND) ? O_APPEND : (tmp ? O_EXCL :
 
1389
                O_TRUNC)), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
 
1390
                S_IROTH | S_IWOTH);
1582
1391
 
1583
1392
        /* Set the umask back to the user's original value. */
1584
1393
        umask(original_umask);
1594
1403
            goto cleanup_and_exit;
1595
1404
        }
1596
1405
 
1597
 
        f = fdopen(fd, (append == 1) ? "ab" : "wb");
 
1406
        f = fdopen(fd, (append == APPEND) ? "ab" : "wb");
1598
1407
 
1599
1408
        if (f == NULL) {
1600
1409
            statusbar(_("Error writing %s: %s"), realname,
1606
1415
 
1607
1416
    /* There might not be a magicline.  There won't be when writing out
1608
1417
     * a selection. */
1609
 
    assert(fileage != NULL && filebot != NULL);
 
1418
    assert(openfile->fileage != NULL && openfile->filebot != NULL);
1610
1419
 
1611
 
    while (fileptr != filebot) {
 
1420
    while (fileptr != openfile->filebot) {
1612
1421
        size_t data_len = strlen(fileptr->data), size;
1613
1422
 
1614
1423
        /* Newlines to nulls, just before we write to disk. */
1627
1436
        }
1628
1437
 
1629
1438
#ifndef NANO_SMALL
1630
 
        if (fmt == DOS_FILE || fmt == MAC_FILE) {
 
1439
        if (openfile->fmt == DOS_FILE || openfile->fmt == MAC_FILE) {
1631
1440
            if (putc('\r', f) == EOF) {
1632
1441
                statusbar(_("Error writing %s: %s"), realname,
1633
1442
                        strerror(errno));
1636
1445
            }
1637
1446
        }
1638
1447
 
1639
 
        if (fmt != MAC_FILE) {
 
1448
        if (openfile->fmt != MAC_FILE) {
1640
1449
#endif
1641
1450
            if (putc('\n', f) == EOF) {
1642
1451
                statusbar(_("Error writing %s: %s"), realname,
1653
1462
    }
1654
1463
 
1655
1464
    /* If we're prepending, open the temp file, and append it to f. */
1656
 
    if (append == 2) {
 
1465
    if (append == PREPEND) {
1657
1466
        int fd_source;
1658
1467
        FILE *f_source = NULL;
1659
1468
 
1683
1492
        goto cleanup_and_exit;
1684
1493
    }
1685
1494
 
1686
 
    if (!tmp && append == 0) {
 
1495
    if (!tmp && append == OVERWRITE) {
1687
1496
        if (!nonamechange) {
1688
 
            filename = mallocstrcpy(filename, realname);
 
1497
            openfile->filename = mallocstrcpy(openfile->filename,
 
1498
                realname);
1689
1499
#ifdef ENABLE_COLOR
1690
 
            update_color();
1691
 
            if (!ISSET(NO_COLOR_SYNTAX))
 
1500
            /* We might have changed the filename, so update the colors
 
1501
             * to account for it, and then make sure we're using
 
1502
             * them. */
 
1503
            color_update();
 
1504
            color_init();
 
1505
 
 
1506
            /* If color syntaxes are available and turned on, we need to
 
1507
             * call edit_refresh(). */
 
1508
            if (openfile->colorstrings != NULL &&
 
1509
                !ISSET(NO_COLOR_SYNTAX))
1692
1510
                edit_refresh();
1693
1511
#endif
1694
1512
        }
1695
1513
 
1696
1514
#ifndef NANO_SMALL
1697
 
        /* Update originalfilestat to reference the file as it is now. */
1698
 
        stat(filename, &originalfilestat);
 
1515
        /* Update current_stat to reference the file as it is now. */
 
1516
        if (openfile->current_stat == NULL)
 
1517
            openfile->current_stat =
 
1518
                (struct stat *)nmalloc(sizeof(struct stat));
 
1519
        stat(realname, openfile->current_stat);
1699
1520
#endif
 
1521
 
1700
1522
        statusbar(P_("Wrote %lu line", "Wrote %lu lines",
1701
1523
                (unsigned long)lineswritten),
1702
1524
                (unsigned long)lineswritten);
1703
 
        UNSET(MODIFIED);
 
1525
        openfile->modified = FALSE;
1704
1526
        titlebar(NULL);
1705
1527
    }
1706
1528
 
1714
1536
}
1715
1537
 
1716
1538
#ifndef NANO_SMALL
1717
 
/* Write a marked selection from a file out.  First, set fileage and
1718
 
 * filebot as the top and bottom of the mark, respectively.  Then call
1719
 
 * write_file() with the values of name, f_open, temp, and append, and
1720
 
 * with nonamechange set to TRUE so that we don't change the current
1721
 
 * filename.  Finally, set fileage and filebot back to their old values
1722
 
 * and return. */
1723
 
int write_marked(const char *name, FILE *f_open, bool tmp, int append)
 
1539
/* Write a marked selection from a file out. */
 
1540
int write_marked_file(const char *name, FILE *f_open, bool tmp,
 
1541
        append_type append)
1724
1542
{
1725
1543
    int retval = -1;
1726
 
    bool old_modified = ISSET(MODIFIED);
1727
 
        /* write_file() unsets the MODIFIED flag. */
 
1544
    bool old_modified = openfile->modified;
 
1545
        /* write_file() unsets the modified flag. */
1728
1546
    bool added_magicline;
1729
1547
        /* Whether we added a magicline after filebot. */
1730
1548
    filestruct *top, *bot;
1731
1549
    size_t top_x, bot_x;
1732
1550
 
 
1551
    assert(openfile->mark_set);
 
1552
 
1733
1553
    /* Partition the filestruct so that it contains only the marked
1734
1554
     * text. */
1735
1555
    mark_order((const filestruct **)&top, &top_x,
1739
1559
    /* If the line at filebot is blank, treat it as the magicline and
1740
1560
     * hence the end of the file.  Otherwise, add a magicline and treat
1741
1561
     * it as the end of the file. */
1742
 
    added_magicline = (filebot->data[0] != '\0');
 
1562
    added_magicline = (openfile->filebot->data[0] != '\0');
1743
1563
    if (added_magicline)
1744
1564
        new_magicline();
1745
1565
 
1762
1582
 
1763
1583
int do_writeout(bool exiting)
1764
1584
{
1765
 
    int i;
1766
 
    int retval = 0, append = 0;
 
1585
    int i, retval = 0;
 
1586
    append_type append = OVERWRITE;
1767
1587
    char *ans;
1768
1588
        /* The last answer the user typed on the statusbar. */
1769
1589
#ifdef NANO_EXTRA
1770
 
    static bool did_cred = FALSE;
 
1590
    static bool did_credits = FALSE;
1771
1591
#endif
1772
1592
 
1773
1593
    currshortcut = writefile_list;
1774
1594
 
1775
 
    if (exiting && filename[0] != '\0' && ISSET(TEMP_FILE)) {
1776
 
        retval = write_file(filename, NULL, FALSE, 0, FALSE);
 
1595
    if (exiting && openfile->filename[0] != '\0' && ISSET(TEMP_FILE)) {
 
1596
        retval = write_file(openfile->filename, NULL, FALSE, OVERWRITE,
 
1597
                FALSE);
1777
1598
 
1778
1599
        /* Write succeeded. */
1779
1600
        if (retval == 0)
1780
1601
            return retval;
1781
1602
    }
1782
1603
 
 
1604
    ans = mallocstrcpy(NULL,
1783
1605
#ifndef NANO_SMALL
1784
 
    if (ISSET(MARK_ISSET) && !exiting)
1785
 
        ans = mallocstrcpy(NULL, "");
1786
 
    else
 
1606
        (openfile->mark_set && !exiting) ? "" :
1787
1607
#endif
1788
 
        ans = mallocstrcpy(NULL, filename);
 
1608
        openfile->filename);
1789
1609
 
1790
1610
    while (TRUE) {
1791
1611
        const char *msg;
1792
1612
#ifndef NANO_SMALL
1793
1613
        const char *formatstr, *backupstr;
1794
1614
 
1795
 
        if (fmt == DOS_FILE)
1796
 
           formatstr = N_(" [DOS Format]");
1797
 
        else if (fmt == MAC_FILE)
1798
 
           formatstr = N_(" [Mac Format]");
1799
 
        else
1800
 
           formatstr = "";
1801
 
 
1802
 
        if (ISSET(BACKUP_FILE))
1803
 
           backupstr = N_(" [Backup]");
1804
 
        else
1805
 
           backupstr = "";
1806
 
 
1807
 
        /* Be nice to the translation folks. */
1808
 
        if (ISSET(MARK_ISSET) && !exiting) {
1809
 
            if (append == 2)
1810
 
                msg = N_("Prepend Selection to File");
1811
 
            else if (append == 1)
1812
 
                msg = N_("Append Selection to File");
1813
 
            else
1814
 
                msg = N_("Write Selection to File");
1815
 
        } else
 
1615
        formatstr = (openfile->fmt == DOS_FILE) ?
 
1616
                N_(" [DOS Format]") : (openfile->fmt == MAC_FILE) ?
 
1617
                N_(" [Mac Format]") : "";
 
1618
 
 
1619
        backupstr = ISSET(BACKUP_FILE) ? N_(" [Backup]") : "";
 
1620
 
 
1621
        if (openfile->mark_set && !exiting)
 
1622
            msg = (append == PREPEND) ?
 
1623
                N_("Prepend Selection to File") : (append == APPEND) ?
 
1624
                N_("Append Selection to File") :
 
1625
                N_("Write Selection to File");
 
1626
        else
1816
1627
#endif /* !NANO_SMALL */
1817
 
        if (append == 2)
1818
 
            msg = N_("File Name to Prepend to");
1819
 
        else if (append == 1)
1820
 
            msg = N_("File Name to Append to");
1821
 
        else
1822
 
            msg = N_("File Name to Write");
 
1628
            msg = (append == PREPEND) ? N_("File Name to Prepend to") :
 
1629
                (append == APPEND) ? N_("File Name to Append to") :
 
1630
                N_("File Name to Write");
1823
1631
 
1824
1632
        /* If we're using restricted mode, the filename isn't blank,
1825
1633
         * and we're at the "Write File" prompt, disable tab
1826
1634
         * completion. */
1827
 
        i = statusq(!ISSET(RESTRICTED) || filename[0] == '\0',
1828
 
                writefile_list, ans,
 
1635
        i = statusq(!ISSET(RESTRICTED) ||
 
1636
                openfile->filename[0] == '\0', writefile_list, ans,
1829
1637
#ifndef NANO_SMALL
1830
1638
                NULL, "%s%s%s", _(msg), formatstr, backupstr
1831
1639
#else
1848
1656
 
1849
1657
                if (tmp == NULL)
1850
1658
                    continue;
 
1659
 
1851
1660
                free(answer);
1852
1661
                answer = tmp;
1853
1662
 
1858
1667
#endif /* !DISABLE_BROWSER */
1859
1668
#ifndef NANO_SMALL
1860
1669
            if (i == TOGGLE_DOS_KEY) {
1861
 
                fmt = (fmt == DOS_FILE) ? NIX_FILE : DOS_FILE;
 
1670
                openfile->fmt = (openfile->fmt == DOS_FILE) ? NIX_FILE :
 
1671
                        DOS_FILE;
1862
1672
                continue;
1863
1673
            } else if (i == TOGGLE_MAC_KEY) {
1864
 
                fmt = (fmt == MAC_FILE) ? NIX_FILE : MAC_FILE;
 
1674
                openfile->fmt = (openfile->fmt == MAC_FILE) ? NIX_FILE :
 
1675
                        MAC_FILE;
1865
1676
                continue;
1866
1677
            } else if (i == TOGGLE_BACKUP_KEY) {
1867
1678
                TOGGLE(BACKUP_FILE);
1869
1680
            } else
1870
1681
#endif /* !NANO_SMALL */
1871
1682
            if (i == NANO_PREPEND_KEY) {
1872
 
                append = (append == 2) ? 0 : 2;
 
1683
                append = (append == PREPEND) ? OVERWRITE : PREPEND;
1873
1684
                continue;
1874
1685
            } else if (i == NANO_APPEND_KEY) {
1875
 
                append = (append == 1) ? 0 : 1;
 
1686
                append = (append == APPEND) ? OVERWRITE : APPEND;
1876
1687
                continue;
1877
1688
            }
1878
1689
 
1882
1693
 
1883
1694
#ifdef NANO_EXTRA
1884
1695
            if (exiting && !ISSET(TEMP_FILE) &&
1885
 
                strcasecmp(answer, "zzy") == 0 && !did_cred) {
 
1696
                strcasecmp(answer, "zzy") == 0 && !did_credits) {
1886
1697
                do_credits();
1887
 
                did_cred = TRUE;
 
1698
                did_credits = TRUE;
1888
1699
                retval = -1;
1889
1700
                break;
1890
1701
            }
1891
1702
#endif
1892
 
            if (append == 0 && strcmp(answer, filename) != 0) {
 
1703
            if (append == OVERWRITE && strcmp(answer,
 
1704
                openfile->filename) != 0) {
1893
1705
                struct stat st;
1894
1706
 
1895
1707
                if (!stat(answer, &st)) {
1897
1709
                    if (i == 0 || i == -1)
1898
1710
                        continue;
1899
1711
                /* If we're using restricted mode, we aren't allowed to
1900
 
                 * change the name of a file once it has one because
 
1712
                 * change the name of a file once it has one, because
1901
1713
                 * that would allow reading from or writing to files not
1902
1714
                 * specified on the command line.  In this case, don't
1903
1715
                 * bother showing the "Different Name" prompt. */
1904
 
                } else if (!ISSET(RESTRICTED) && filename[0] != '\0'
 
1716
                } else if (!ISSET(RESTRICTED) &&
 
1717
                        openfile->filename[0] != '\0'
1905
1718
#ifndef NANO_SMALL
1906
 
                        && (exiting || !ISSET(MARK_ISSET))
 
1719
                        && (exiting || !openfile->mark_set)
1907
1720
#endif
1908
1721
                        ) {
1909
1722
                    i = do_yesno(FALSE,
1918
1731
             * a separate file.  If we're using restricted mode, this is
1919
1732
             * disabled since it allows reading from or writing to files
1920
1733
             * not specified on the command line. */
1921
 
            if (!ISSET(RESTRICTED) && !exiting && ISSET(MARK_ISSET))
1922
 
                retval = write_marked(answer, NULL, FALSE, append);
 
1734
            if (!ISSET(RESTRICTED) && !exiting && openfile->mark_set)
 
1735
                retval = write_marked_file(answer, NULL, FALSE, append);
1923
1736
            else
1924
1737
#endif /* !NANO_SMALL */
1925
1738
                retval = write_file(answer, NULL, FALSE, append, FALSE);
1926
1739
 
1927
 
#ifdef ENABLE_MULTIBUFFER
1928
 
            /* If we're not about to exit, update the current entry in
1929
 
             * the open_files structure. */
1930
 
            if (!exiting)
1931
 
                add_open_file(TRUE);
1932
 
#endif
1933
 
 
1934
1740
            break;
1935
1741
        }
1936
1742
    } /* while (TRUE) */
1952
1758
{
1953
1759
    char *dirtmp = NULL;
1954
1760
 
1955
 
    if (buf == NULL)
1956
 
        return NULL;
 
1761
    assert(buf != NULL);
1957
1762
 
1958
1763
    if (buf[0] == '~') {
1959
1764
        size_t i;
2097
1902
char **cwd_tab_completion(const char *buf, size_t *num_matches, size_t
2098
1903
        buflen)
2099
1904
{
2100
 
    char *dirname = mallocstrcpy(NULL, buf);
2101
 
    char *filename;
 
1905
    char *dirname = mallocstrcpy(NULL, buf), *filename;
2102
1906
#ifndef DISABLE_OPERATINGDIR
2103
1907
    size_t dirnamelen;
2104
1908
#endif
2146
1950
    filenamelen = strlen(filename);
2147
1951
 
2148
1952
    while ((nextdir = readdir(dir)) != NULL) {
2149
 
 
2150
1953
#ifdef DEBUG
2151
1954
        fprintf(stderr, "Comparing \'%s\'\n", nextdir->d_name);
2152
1955
#endif
2181
1984
            ++(*num_matches);
2182
1985
        }
2183
1986
    }
 
1987
 
2184
1988
    closedir(dir);
2185
1989
    free(dirname);
2186
1990
    free(filename);
2227
2031
 
2228
2032
        while (TRUE) {
2229
2033
            for (match = 1; match < num_matches; match++) {
 
2034
                /* Get the number of single-byte characters that all the
 
2035
                 * matches have in common. */
2230
2036
                match1_mb_len = parse_mbchar(matches[0] + common_len,
2231
 
                        match1_mb, NULL, NULL);
 
2037
                        match1_mb, NULL);
2232
2038
                match2_mb_len = parse_mbchar(matches[match] +
2233
 
                        common_len, match2_mb, NULL, NULL);
 
2039
                        common_len, match2_mb, NULL);
2234
2040
                match1_mb[match1_mb_len] = '\0';
2235
2041
                match2_mb[match2_mb_len] = '\0';
2236
2042
                if (strcmp(match1_mb, match2_mb) != 0)
2240
2046
            if (match < num_matches || matches[0][common_len] == '\0')
2241
2047
                break;
2242
2048
 
2243
 
            common_len += parse_mbchar(buf + common_len, NULL, NULL,
2244
 
                NULL);
 
2049
            common_len += parse_mbchar(buf + common_len, NULL, NULL);
2245
2050
        }
2246
2051
 
2247
2052
        free(match1_mb);
2267
2072
            beep();
2268
2073
 
2269
2074
        /* If there is more of a match to display on the statusbar, show
2270
 
         * it.  We reset lastwastab to FALSE: it requires hitting Tab
 
2075
         * it.  We reset lastwastab to FALSE: it requires pressing Tab
2271
2076
         * twice in succession with no statusbar changes to see a match
2272
2077
         * list. */
2273
2078
        if (common_len != *place) {
2282
2087
        } else if (*lastwastab == FALSE || num_matches < 2)
2283
2088
            *lastwastab = TRUE;
2284
2089
        else {
2285
 
            int longest_name = 0, editline = 0;
2286
 
            size_t columns;
 
2090
            int longest_name = 0, columns, editline = 0;
2287
2091
 
2288
2092
            /* Now we show a list of the available choices. */
2289
2093
            assert(num_matches > 1);
2305
2109
 
2306
2110
            assert(longest_name <= COLS - 1);
2307
2111
 
2308
 
            /* Each column will be longest_name + 2 characters wide,
2309
 
             * i.e, two spaces between columns, except that there will
2310
 
             * be only one space after the last column. */
 
2112
            /* Each column will be (longest_name + 2) columns wide, i.e,
 
2113
             * two spaces between columns, except that there will be
 
2114
             * only one space after the last column. */
2311
2115
            columns = (COLS + 1) / (longest_name + 2);
2312
2116
 
2313
2117
            /* Blank the edit window, and print the matches out
2339
2143
                if ((match + 1) % columns == 0)
2340
2144
                    editline++;
2341
2145
            }
2342
 
            wrefresh(edit);
 
2146
 
 
2147
            wnoutrefresh(edit);
2343
2148
            *list = TRUE;
2344
2149
        }
2345
2150
 
2462
2267
    curs_set(0);
2463
2268
    blank_statusbar();
2464
2269
    bottombars(browser_list);
2465
 
    wrefresh(bottomwin);
 
2270
    wnoutrefresh(bottomwin);
2466
2271
 
2467
2272
#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
2468
2273
    /* Set currshortcut so the user can click in the shortcut area, and
2747
2552
                if (j == selected)
2748
2553
                    wattron(edit, A_REVERSE);
2749
2554
 
2750
 
                mvwaddnstr(edit, editline, col, hblank, longest);
 
2555
                blank_line(edit, editline, col, longest);
2751
2556
                mvwaddstr(edit, editline, col, disp);
2752
2557
                free(disp);
2753
2558
 
2808
2613
            free(foo);
2809
2614
        }
2810
2615
 
2811
 
        wrefresh(edit);
 
2616
        wnoutrefresh(edit);
2812
2617
    } while ((kbinput = get_kbinput(edit, &meta_key, &func_key)) !=
2813
2618
        NANO_EXIT_KEY && kbinput != NANO_EXIT_FKEY);
2814
2619
 
2899
2704
    return nanohist;
2900
2705
}
2901
2706
 
 
2707
/* Load histories from ~/.nano_history. */
2902
2708
void load_history(void)
2903
2709
{
2904
2710
    char *nanohist = histfilename();