#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <utime.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <pwd.h>
#include <assert.h>
#include "proto.h"
#include "nano.h"
#ifndef PATH_MAX
#define PATH_MAX -1
#endif
#ifndef NANO_SMALL
static int fileformat = 0;
#endif
void load_file(int update)
{
current = fileage;
#ifdef ENABLE_MULTIBUFFER
add_open_file(update);
#endif
#ifdef ENABLE_COLOR
update_color();
edit_refresh();
#endif
}
void new_file(void)
{
fileage = make_new_node(NULL);
fileage->data = charalloc(1);
fileage->data[0] = '\0';
filebot = fileage;
edittop = fileage;
editbot = fileage;
current = fileage;
current_x = 0;
totlines = 1;
totsize = 0;
#ifdef ENABLE_MULTIBUFFER
if (open_files == NULL) {
add_open_file(0);
UNSET(VIEW_MODE);
}
#else
UNSET(VIEW_MODE);
#endif
#ifdef ENABLE_COLOR
update_color();
edit_refresh();
#endif
}
filestruct *read_line(char *buf, filestruct *prev, int *line1ins, int len)
{
filestruct *fileptr = (filestruct *)nmalloc(sizeof(filestruct));
unsunder(buf, len);
assert(strlen(buf) == len);
fileptr->data = mallocstrcpy(NULL, buf);
#ifndef NANO_SMALL
if (!ISSET(NO_CONVERT) && len > 0 && buf[len - 1] == '\r') {
fileptr->data[len - 1] = '\0';
totsize--;
if (fileformat == 0)
fileformat = 1;
}
#endif
if (*line1ins != 0 || fileage == NULL) {
fileptr->prev = NULL;
fileptr->next = fileage;
fileptr->lineno = 1;
if (*line1ins != 0) {
*line1ins = 0;
edittop = fileptr;
} else
filebot = fileptr;
fileage = fileptr;
} else {
assert(prev != NULL);
fileptr->prev = prev;
fileptr->next = NULL;
fileptr->lineno = prev->lineno + 1;
prev->next = fileptr;
}
return fileptr;
}
int read_file(FILE *f, const char *filename, int quiet)
{
int num_lines = 0, len = 0;
char input = '\0';
char *buf;
long i = 0, bufx = 128;
filestruct *fileptr = current, *tmp = NULL;
#ifndef NANO_SMALL
int old_no_convert = ISSET(NO_CONVERT);
#endif
int line1ins = 0;
int input_int;
#ifndef NANO_SMALL
jumpok = 0;
#endif
buf = charalloc(bufx);
buf[0] = '\0';
if (current != NULL) {
if (current == fileage)
line1ins = 1;
else
fileptr = current->prev;
tmp = fileptr;
}
assert(current != NULL || fileage == NULL);
while ((input_int = getc(f)) != EOF) {
input = (char)input_int;
#ifndef NANO_SMALL
if (fileformat == 0 && !ISSET(NO_CONVERT)
&& is_cntrl_char((int)input) != 0 && input != '\t'
&& input != '\r' && input != '\n')
SET(NO_CONVERT);
#endif
if (input == '\n') {
fileptr = read_line(buf, fileptr, &line1ins, len);
len = 0;
num_lines++;
buf[0] = '\0';
i = 0;
#ifndef NANO_SMALL
} else if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r') {
fileformat = 2;
fileptr = read_line(buf, fileptr, &line1ins, len);
len = 1;
num_lines++;
totsize++;
buf[0] = input;
buf[1] = '\0';
i = 1;
#endif
} else {
len++;
if (i >= bufx - 1) {
bufx += 128;
buf = charealloc(buf, bufx);
}
buf[i] = input;
buf[i + 1] = '\0';
i++;
}
totsize++;
}
if (ferror(f))
nperror(filename);
fclose(f);
if (len > 0) {
#ifndef NANO_SMALL
if (!ISSET(NO_CONVERT) && buf[len - 1] == '\r' && fileformat == 0)
fileformat = 2;
#endif
fileptr = read_line(buf, fileptr, &line1ins, len);
num_lines++;
totsize++;
buf[0] = '\0';
}
#ifndef NANO_SMALL
else if (!ISSET(NO_CONVERT) && input == '\r') {
buf[0] = input;
buf[1] = '\0';
len = 1;
fileptr = read_line(buf, fileptr, &line1ins, len);
num_lines++;
totsize++;
buf[0] = '\0';
}
#endif
free(buf);
#ifndef NANO_SMALL
if (!old_no_convert && ISSET(NO_CONVERT))
UNSET(NO_CONVERT);
#endif
if (totsize == 0 || fileptr == NULL)
new_file();
if (num_lines != 0) {
if (current != NULL) {
fileptr->next = current;
current->prev = fileptr;
renumber(current);
current_x = 0;
placewewant = 0;
} else if (fileptr->next == NULL) {
filebot = fileptr;
new_magicline();
totsize--;
load_file(quiet);
}
}
#ifndef NANO_SMALL
if (fileformat == 2)
statusbar(P_("Read %d line (Converted from Mac format)",
"Read %d lines (Converted from Mac format)",
num_lines), num_lines);
else if (fileformat == 1)
statusbar(P_("Read %d line (Converted from DOS format)",
"Read %d lines (Converted from DOS format)",
num_lines), num_lines);
else
#endif
statusbar(P_("Read %d line", "Read %d lines", num_lines),
num_lines);
#ifndef NANO_SMALL
fileformat = 0;
#endif
totlines += num_lines;
#ifndef NANO_SMALL
jumpok = 1;
#endif
return 1;
}
int open_file(const char *filename, int insert, int quiet)
{
int fd;
FILE *f;
struct stat fileinfo;
if (filename[0] == '\0' || stat(filename, &fileinfo) == -1) {
if (insert && !quiet) {
statusbar(_("\"%s\" not found"), filename);
return -1;
} else {
statusbar(_("New File"));
new_file();
}
} else if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
S_ISBLK(fileinfo.st_mode)) {
statusbar(S_ISDIR(fileinfo.st_mode) ? _("\"%s\" is a directory") :
_("File \"%s\" is a device file"), filename);
if (!insert)
new_file();
return -1;
} else if ((fd = open(filename, O_RDONLY)) == -1) {
if (!quiet
#ifdef ENABLE_MULTIBUFFER
|| ISSET(MULTIBUFFER)
#endif
)
statusbar("%s: %s", strerror(errno), filename);
if (!insert)
new_file();
return -1;
} else {
if (!quiet)
statusbar(_("Reading File"));
f = fdopen(fd, "rb");
if (f == NULL) {
nperror("fdopen");
close(fd);
return -1;
}
read_file(f, filename, quiet);
#ifndef NANO_SMALL
stat(filename, &originalfilestat);
#endif
}
return 1;
}
char *get_next_filename(const char *name)
{
int i = 0;
char *buf = NULL;
struct stat fs;
buf = charalloc(strlen(name) + num_of_digits(INT_MAX) + 2);
strcpy(buf, name);
while (1) {
if (stat(buf, &fs) == -1)
return buf;
if (i == INT_MAX)
break;
i++;
strcpy(buf, name);
sprintf(&buf[strlen(name)], ".%d", i);
}
buf[0] = '\0';
return buf;
}
int do_insertfile(int loading_file)
{
int i, old_current_x = current_x;
char *realname = NULL;
static char *inspath = NULL;
if (inspath == NULL) {
inspath = charalloc(1);
inspath[0] = '\0';
}
wrap_reset();
#if !defined(DISABLE_BROWSER) || !defined(NANO_SMALL) && defined(ENABLE_MULTIBUFFER)
start_again:
#endif
#if !defined(DISABLE_BROWSER) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
currshortcut = insertfile_list;
#endif
#ifndef DISABLE_OPERATINGDIR
if (operating_dir != NULL && strcmp(operating_dir, ".") != 0)
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER))
i = statusq(1, insertfile_list, inspath,
#ifndef NANO_SMALL
0,
#endif
_("File to insert into new buffer [from %s] "),
operating_dir);
else
#endif
i = statusq(1, insertfile_list, inspath,
#ifndef NANO_SMALL
0,
#endif
_("File to insert [from %s] "),
operating_dir);
else
#endif
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER))
i = statusq(1, insertfile_list, inspath,
#ifndef NANO_SMALL
0,
#endif
_("File to insert into new buffer [from ./] "));
else
#endif
i = statusq(1, insertfile_list, inspath,
#ifndef NANO_SMALL
0,
#endif
_("File to insert [from ./] "));
if (i != -1) {
inspath = mallocstrcpy(inspath, answer);
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", answer);
#endif
#ifndef NANO_SMALL
#ifdef ENABLE_MULTIBUFFER
if (i == TOGGLE_LOAD_KEY) {
if (!ISSET(VIEW_MODE))
TOGGLE(MULTIBUFFER);
loading_file = ISSET(MULTIBUFFER);
goto start_again;
}
#endif
if (i == NANO_EXTCMD_KEY) {
int ts = statusq(TRUE, extcmd_list, "", NULL,
_("Command to execute"));
if (ts == -1 || answer == NULL || answer[0] == '\0') {
statusbar(_("Cancelled"));
display_main_list();
return 0;
}
}
#endif
#ifndef DISABLE_BROWSER
if (i == NANO_TOFILES_KEY) {
char *tmp = do_browse_from(answer);
if (tmp != NULL) {
free(answer);
answer = tmp;
resetstatuspos = 1;
} else
goto start_again;
}
#endif
#ifndef DISABLE_OPERATINGDIR
if (i != NANO_EXTCMD_KEY && check_operating_dir(answer, FALSE)) {
statusbar(_("Can't insert file from outside of %s"),
operating_dir);
return 0;
}
#endif
#ifdef ENABLE_MULTIBUFFER
if (loading_file) {
add_open_file(1);
new_file();
UNSET(MODIFIED);
#ifndef NANO_SMALL
UNSET(MARK_ISSET);
#endif
}
#endif
#ifndef NANO_SMALL
if (i == NANO_EXTCMD_KEY) {
realname = mallocstrcpy(realname, "");
i = open_pipe(answer);
} else
#endif
{
realname = real_dir_from_tilde(answer);
i = open_file(realname, 1, loading_file);
}
#ifdef ENABLE_MULTIBUFFER
if (loading_file) {
if (i == -1) {
free(realname);
free(fileage);
load_open_file();
goto skip_insert;
} else
filename = mallocstrcpy(filename, realname);
}
#endif
free(realname);
#ifdef DEBUG
dump_buffer(fileage);
#endif
#ifdef ENABLE_MULTIBUFFER
if (loading_file)
load_file(0);
else
#endif
set_modified();
fix_editbot();
#ifdef ENABLE_MULTIBUFFER
if (loading_file) {
clearok(topwin, FALSE);
titlebar(NULL);
shortcut_init(0);
}
#endif
#ifdef ENABLE_MULTIBUFFER
if (!loading_file) {
#endif
current_x = old_current_x;
#ifdef ENABLE_MULTIBUFFER
}
#endif
if (current->lineno > editbot->lineno)
edit_update(current, CENTER);
else
edit_refresh();
} else {
statusbar(_("Cancelled"));
i = 0;
}
#ifdef ENABLE_MULTIBUFFER
skip_insert:
#endif
free(inspath);
inspath = NULL;
display_main_list();
return i;
}
int do_insertfile_void(void)
{
int result = 0;
#ifdef ENABLE_MULTIBUFFER
if (ISSET(VIEW_MODE)) {
if (ISSET(MULTIBUFFER))
result = do_insertfile(1);
else
statusbar(_("Key illegal in non-multibuffer mode"));
}
else
result = do_insertfile(ISSET(MULTIBUFFER));
#else
result = do_insertfile(0);
#endif
display_main_list();
return result;
}
#ifdef ENABLE_MULTIBUFFER
openfilestruct *make_new_opennode(openfilestruct *prevnode)
{
openfilestruct *newnode = (openfilestruct *)nmalloc(sizeof(openfilestruct));
newnode->filename = NULL;
newnode->fileage = NULL;
newnode->filebot = NULL;
newnode->prev = prevnode;
newnode->next = NULL;
return newnode;
}
void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
openfilestruct *end)
{
newnode->next = end;
newnode->prev = begin;
begin->next = newnode;
if (end != NULL)
end->prev = newnode;
}
void unlink_opennode(const openfilestruct *fileptr)
{
assert(fileptr != NULL);
if (fileptr->prev != NULL)
fileptr->prev->next = fileptr->next;
if (fileptr->next != NULL)
fileptr->next->prev = fileptr->prev;
}
void delete_opennode(openfilestruct *fileptr)
{
if (fileptr != NULL) {
if (fileptr->filename != NULL)
free(fileptr->filename);
if (fileptr->fileage != NULL)
free_filestruct(fileptr->fileage);
free(fileptr);
}
}
void free_openfilestruct(openfilestruct *src)
{
if (src != NULL) {
while (src->next != NULL) {
src = src->next;
delete_opennode(src->prev);
#ifdef DEBUG
fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_opennode()");
#endif
}
delete_opennode(src);
#ifdef DEBUG
fprintf(stderr, "%s: free'd last node.\n", "delete_opennode()");
#endif
}
}
int add_open_file(int update)
{
openfilestruct *tmp;
if (fileage == NULL || current == NULL || filename == NULL)
return 1;
if (open_files == NULL)
open_files = make_new_opennode(NULL);
else if (!update) {
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
#endif
tmp = make_new_opennode(NULL);
splice_opennode(open_files, tmp, open_files->next);
open_files = open_files->next;
}
open_files->filename = mallocstrcpy(open_files->filename, filename);
#ifndef NANO_SMALL
open_files->originalfilestat = originalfilestat;
#endif
open_files->file_totlines = totlines;
open_files->file_totsize = totsize;
open_files->file_current_x = current_x;
open_files->file_current_y = current_y;
open_files->file_placewewant = placewewant;
open_files->file_lineno = current->lineno;
if (update) {
#ifndef NANO_SMALL
open_files->file_flags = (MODIFIED & ISSET(MODIFIED)) | (MARK_ISSET & ISSET(MARK_ISSET));
if (ISSET(MARK_ISSET)) {
open_files->file_mark_beginbuf = mark_beginbuf;
open_files->file_mark_beginx = mark_beginx;
}
#else
open_files->file_flags = (MODIFIED & ISSET(MODIFIED));
#endif
}
if (!(ISSET(VIEW_MODE) && !update)) {
open_files->fileage = fileage;
open_files->filebot = filebot;
}
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
#endif
return 0;
}
int load_open_file(void)
{
if (open_files == NULL)
return 1;
filename = mallocstrcpy(filename, open_files->filename);
#ifndef NANO_SMALL
originalfilestat = open_files->originalfilestat;
#endif
fileage = open_files->fileage;
current = fileage;
filebot = open_files->filebot;
totlines = open_files->file_totlines;
totsize = open_files->file_totsize;
if (open_files->file_flags & MODIFIED)
SET(MODIFIED);
else
UNSET(MODIFIED);
#ifndef NANO_SMALL
if (open_files->file_flags & MARK_ISSET) {
mark_beginbuf = open_files->file_mark_beginbuf;
mark_beginx = open_files->file_mark_beginx;
SET(MARK_ISSET);
} else
UNSET(MARK_ISSET);
#endif
#ifdef ENABLE_COLOR
update_color();
#endif
do_gotopos(open_files->file_lineno, open_files->file_current_x, open_files->file_current_y, open_files->file_placewewant);
clearok(topwin, FALSE);
titlebar(NULL);
return 0;
}
int open_prevfile(int closing_file)
{
if (open_files == NULL)
return 1;
if (!closing_file)
add_open_file(1);
if (open_files->prev == NULL && open_files->next == NULL) {
if (!closing_file)
statusbar(_("No more open files"));
return 1;
}
if (open_files->prev != NULL) {
open_files = open_files->prev;
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
#endif
}
else if (open_files->next != NULL) {
while (open_files->next != NULL)
open_files = open_files->next;
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
#endif
}
load_open_file();
statusbar(_("Switched to %s"),
((open_files->filename[0] == '\0') ? "New Buffer" : open_files->filename));
#ifdef DEBUG
dump_buffer(current);
#endif
return 0;
}
int open_prevfile_void(void)
{
return open_prevfile(0);
}
int open_nextfile(int closing_file)
{
if (open_files == NULL)
return 1;
if (!closing_file)
add_open_file(1);
if (open_files->prev == NULL && open_files->next == NULL) {
if (!closing_file)
statusbar(_("No more open files"));
return 1;
}
if (open_files->next != NULL) {
open_files = open_files->next;
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
#endif
}
else if (open_files->prev != NULL) {
while (open_files->prev != NULL) {
open_files = open_files->prev;
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
#endif
}
}
load_open_file();
statusbar(_("Switched to %s"),
((open_files->filename[0] == '\0') ? "New Buffer" : open_files->filename));
#ifdef DEBUG
dump_buffer(current);
#endif
return 0;
}
int open_nextfile_void(void)
{
return open_nextfile(0);
}
int close_open_file(void)
{
openfilestruct *tmp;
if (open_files == NULL)
return 1;
open_files->fileage = fileage;
open_files->filebot = filebot;
tmp = open_files;
if (open_nextfile(1)) {
if (open_prevfile(1))
return 1;
}
unlink_opennode(tmp);
delete_opennode(tmp);
shortcut_init(0);
display_main_list();
return 0;
}
#endif
#if !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR)
char *get_full_path(const char *origpath)
{
char *newpath = NULL, *last_slash, *d_here, *d_there, *d_there_file, tmp;
int path_only, last_slash_index;
struct stat fileinfo;
char *expanded_origpath;
#ifdef PATH_MAX
d_here = getcwd(NULL, PATH_MAX + 1);
#else
d_here = getcwd(NULL, 0);
#endif
if (d_here != NULL) {
align(&d_here);
if (strcmp(d_here, "/")) {
d_here = charealloc(d_here, strlen(d_here) + 2);
strcat(d_here, "/");
}
path_only = !stat(origpath, &fileinfo) && S_ISDIR(fileinfo.st_mode);
expanded_origpath = real_dir_from_tilde(origpath);
d_there = mallocstrcpy(NULL, expanded_origpath);
d_there_file = mallocstrcpy(NULL, expanded_origpath);
free(expanded_origpath);
if (path_only) {
tmp = d_there[strlen(d_there) - 1];
if (tmp != '/') {
d_there = charealloc(d_there, strlen(d_there) + 2);
strcat(d_there, "/");
d_there_file = charealloc(d_there_file, strlen(d_there_file) + 2);
strcat(d_there_file, "/");
}
}
last_slash = strrchr(d_there, '/');
if (last_slash == NULL)
d_there = mallocstrcpy(d_there, d_here);
else {
last_slash_index = strlen(d_there) - strlen(last_slash);
null_at(&d_there, last_slash_index + 1);
if (!path_only) {
last_slash = strrchr(d_there_file, '/');
last_slash++;
strcpy(d_there_file, last_slash);
align(&d_there_file);
}
if (chdir(d_there) != -1) {
free(d_there);
#ifdef PATH_MAX
d_there = getcwd(NULL, PATH_MAX + 1);
#else
d_there = getcwd(NULL, 0);
#endif
align(&d_there);
if (d_there != NULL) {
if (strcmp(d_there, "/")) {
d_there = charealloc(d_there, strlen(d_there) + 2);
strcat(d_there, "/");
}
}
else
return NULL;
}
chdir(d_here);
}
if (!path_only) {
newpath = charalloc(strlen(d_there) + strlen(d_there_file) + 1);
strcpy(newpath, d_there);
strcat(newpath, d_there_file);
}
else {
newpath = charalloc(strlen(d_there) + 1);
strcpy(newpath, d_there);
}
free(d_there_file);
free(d_there);
free(d_here);
}
return newpath;
}
#endif
#ifndef DISABLE_SPELLER
char *check_writable_directory(const char *path)
{
char *full_path = get_full_path(path);
int writable;
struct stat fileinfo;
if (full_path == NULL)
return NULL;
writable = !stat(full_path, &fileinfo) && (fileinfo.st_mode & S_IWUSR);
if (full_path[strlen(full_path) - 1] != '/' || writable == 0) {
free(full_path);
return NULL;
}
return full_path;
}
char *safe_tempnam(const char *dirname, const char *filename_prefix)
{
char *full_tempdir = NULL;
const char *TMPDIR_env;
int filedesc;
TMPDIR_env = getenv("TMPDIR");
if (TMPDIR_env != NULL && TMPDIR_env[0] != '\0')
full_tempdir = check_writable_directory(TMPDIR_env);
if (full_tempdir == NULL && dirname != NULL)
full_tempdir = check_writable_directory(dirname);
if (full_tempdir == NULL)
full_tempdir = check_writable_directory(P_tmpdir);
if (full_tempdir == NULL) {
full_tempdir = charalloc(6);
strcpy(full_tempdir, "/tmp/");
}
full_tempdir = charealloc(full_tempdir, strlen(full_tempdir) + 12);
strncat(full_tempdir, filename_prefix, 5);
strcat(full_tempdir, "XXXXXX");
filedesc = mkstemp(full_tempdir);
if (filedesc != -1) {
close(filedesc);
unlink(full_tempdir);
return full_tempdir;
}
free(full_tempdir);
return NULL;
}
#endif
#ifndef DISABLE_OPERATINGDIR
void init_operating_dir(void)
{
assert(full_operating_dir == NULL);
if (operating_dir == NULL)
return;
full_operating_dir = get_full_path(operating_dir);
if (full_operating_dir == NULL || chdir(full_operating_dir) == -1) {
free(full_operating_dir);
full_operating_dir = NULL;
free(operating_dir);
operating_dir = NULL;
}
}
int check_operating_dir(const char *currpath, int allow_tabcomp)
{
char *fullpath;
int retval = 0;
const char *whereami1, *whereami2 = NULL;
if (operating_dir == NULL)
return 0;
fullpath = get_full_path(currpath);
if (fullpath == NULL)
return 1;
whereami1 = strstr(fullpath, full_operating_dir);
if (allow_tabcomp)
whereami2 = strstr(full_operating_dir, fullpath);
if (whereami1 != fullpath && whereami2 != full_operating_dir)
retval = 1;
free(fullpath);
return retval;
}
#endif
int write_file(const char *name, int tmp, int append, int nonamechange)
{
int retval = -1;
long size;
int lineswritten = 0;
char *buf = NULL;
const filestruct *fileptr;
FILE *f;
int fd;
int mask = 0, realexists, anyexists;
struct stat st, lst;
char *realname = NULL;
if (name[0] == '\0') {
statusbar(_("Cancelled"));
return -1;
}
if (!tmp)
titlebar(NULL);
fileptr = fileage;
realname = real_dir_from_tilde(name);
#ifndef DISABLE_OPERATINGDIR
if (!tmp && operating_dir != NULL && check_operating_dir(realname, 0)) {
statusbar(_("Can't write outside of %s"), operating_dir);
goto cleanup_and_exit;
}
#endif
realexists = stat(realname, &st);
#ifndef NANO_SMALL
if (ISSET(BACKUP_FILE) && !tmp && realexists == 0 &&
(append != 0 || ISSET(MARK_ISSET) ||
originalfilestat.st_mtime == st.st_mtime)) {
FILE *backup_file;
char *backupname = NULL;
char backupbuf[COPYFILEBLOCKSIZE];
size_t bytesread;
struct utimbuf filetime;
filetime.actime = originalfilestat.st_atime;
filetime.modtime = originalfilestat.st_mtime;
f = fopen(realname, "rb");
if (f == NULL) {
statusbar(_("Could not read %s for backup: %s"), realname,
strerror(errno));
return -1;
}
backupname = charalloc(strlen(realname) + 2);
sprintf(backupname, "%s~", realname);
backup_file = fopen(backupname, "wb");
if (backup_file == NULL) {
statusbar(_("Couldn't write backup: %s"), strerror(errno));
free(backupname);
return -1;
}
#ifdef DEBUG
fprintf(stderr, "Backing up %s to %s\n", realname, backupname);
#endif
while ((bytesread = fread(backupbuf, sizeof(char),
COPYFILEBLOCKSIZE, f)) > 0)
if (fwrite(backupbuf, sizeof(char), bytesread, backup_file) <= 0)
break;
fclose(backup_file);
fclose(f);
if (chmod(backupname, originalfilestat.st_mode) == -1)
statusbar(_("Could not set permissions %o on backup %s: %s"),
originalfilestat.st_mode, backupname,
strerror(errno));
if (chown(backupname, originalfilestat.st_uid,
originalfilestat.st_gid) == -1)
statusbar(_("Could not set owner %d/group %d on backup %s: %s"),
originalfilestat.st_uid, originalfilestat.st_gid,
backupname, strerror(errno));
if (utime(backupname, &filetime) == -1)
statusbar(_("Could not set access/modification time on backup %s: %s"),
backupname, strerror(errno));
free(backupname);
}
#endif
anyexists = lstat(realname, &lst);
if (tmp && anyexists != -1)
goto cleanup_and_exit;
else if (append != 2 && (!ISSET(NOFOLLOW_SYMLINKS) || !S_ISLNK(lst.st_mode)
|| tmp)) {
if (append != 0)
fd = open(realname, O_WRONLY | O_CREAT | O_APPEND, (S_IRUSR | S_IWUSR));
else if (tmp)
fd = open(realname, O_WRONLY | O_CREAT | O_EXCL, (S_IRUSR | S_IWUSR));
else
fd = open(realname, O_WRONLY | O_CREAT | O_TRUNC, (S_IRUSR | S_IWUSR));
if (fd == -1) {
if (!tmp && ISSET(TEMP_OPT)) {
UNSET(TEMP_OPT);
retval = do_writeout(filename, 1, 0);
} else
statusbar(_("Could not open file for writing: %s"),
strerror(errno));
goto cleanup_and_exit;
}
}
else {
buf = charalloc(strlen(realname) + 8);
strcpy(buf, realname);
strcat(buf, ".XXXXXX");
if ((fd = mkstemp(buf)) == -1) {
if (ISSET(TEMP_OPT)) {
UNSET(TEMP_OPT);
retval = do_writeout(filename, 1, 0);
} else
statusbar(_("Could not open file for writing: %s"),
strerror(errno));
goto cleanup_and_exit;
}
}
#ifdef DEBUG
dump_buffer(fileage);
#endif
#ifndef NANO_SMALL
jumpok = 0;
#endif
f = fdopen(fd, append == 1 ? "ab" : "wb");
if (f == NULL) {
statusbar(_("Could not open file for writing: %s"), strerror(errno));
goto cleanup_and_exit;
}
while (fileptr != NULL && fileptr->next != NULL) {
int data_len;
if (filebot == fileptr && fileptr->data[0] == '\0')
break;
data_len = strlen(fileptr->data);
sunder(fileptr->data);
size = fwrite(fileptr->data, 1, data_len, f);
unsunder(fileptr->data, data_len);
if (size < data_len) {
statusbar(_("Could not open file for writing: %s"),
strerror(errno));
fclose(f);
goto cleanup_and_exit;
}
#ifdef DEBUG
else
fprintf(stderr, "Wrote >%s\n", fileptr->data);
#endif
#ifndef NANO_SMALL
if (ISSET(DOS_FILE) || ISSET(MAC_FILE))
putc('\r', f);
if (!ISSET(MAC_FILE))
#endif
putc('\n', f);
fileptr = fileptr->next;
lineswritten++;
}
if (fileptr != NULL) {
int data_len = strlen(fileptr->data);
sunder(fileptr->data);
size = fwrite(fileptr->data, 1, data_len, f);
unsunder(fileptr->data, data_len);
if (size < data_len) {
statusbar(_("Could not open file for writing: %s"),
strerror(errno));
goto cleanup_and_exit;
} else if (data_len > 0) {
#ifndef NANO_SMALL
if (ISSET(DOS_FILE) || ISSET(MAC_FILE)) {
if (putc('\r', f) == EOF) {
statusbar(_("Could not open file for writing: %s"),
strerror(errno));
fclose(f);
goto cleanup_and_exit;
}
lineswritten++;
}
if (!ISSET(MAC_FILE))
#endif
{
if (putc('\n', f) == EOF) {
statusbar(_("Could not open file for writing: %s"),
strerror(errno));
fclose(f);
goto cleanup_and_exit;
}
lineswritten++;
}
}
}
if (fclose(f) != 0) {
statusbar(_("Could not close %s: %s"), realname, strerror(errno));
unlink(buf);
goto cleanup_and_exit;
}
if (append == 2) {
int fd_source, fd_dest;
FILE *f_source, *f_dest;
int prechar;
if ((fd_dest = open(buf, O_WRONLY | O_APPEND, (S_IRUSR | S_IWUSR))) == -1) {
statusbar(_("Could not reopen %s: %s"), buf, strerror(errno));
goto cleanup_and_exit;
}
f_dest = fdopen(fd_dest, "wb");
if (f_dest == NULL) {
statusbar(_("Could not reopen %s: %s"), buf, strerror(errno));
close(fd_dest);
goto cleanup_and_exit;
}
if ((fd_source = open(realname, O_RDONLY | O_CREAT)) == -1) {
statusbar(_("Could not open %s for prepend: %s"), realname, strerror(errno));
fclose(f_dest);
goto cleanup_and_exit;
}
f_source = fdopen(fd_source, "rb");
if (f_source == NULL) {
statusbar(_("Could not open %s for prepend: %s"), realname, strerror(errno));
fclose(f_dest);
close(fd_source);
goto cleanup_and_exit;
}
while ((prechar = getc(f_source)) != EOF) {
if (putc(prechar, f_dest) == EOF) {
statusbar(_("Could not open %s for prepend: %s"), realname, strerror(errno));
fclose(f_source);
fclose(f_dest);
goto cleanup_and_exit;
}
}
if (ferror(f_source)) {
statusbar(_("Could not reopen %s: %s"), buf, strerror(errno));
fclose(f_source);
fclose(f_dest);
goto cleanup_and_exit;
}
fclose(f_source);
fclose(f_dest);
}
if (realexists == -1 || tmp ||
(ISSET(NOFOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
mask = umask(0);
umask(mask);
if (tmp)
mask = S_IRUSR | S_IWUSR;
else
mask = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |
S_IWOTH) & ~mask;
} else
mask = st.st_mode;
if (append == 2 ||
(!tmp && (ISSET(NOFOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode)))) {
if (unlink(realname) == -1) {
if (errno != ENOENT) {
statusbar(_("Could not open %s for writing: %s"),
realname, strerror(errno));
unlink(buf);
goto cleanup_and_exit;
}
}
if (link(buf, realname) != -1)
unlink(buf);
else if (errno != EPERM) {
statusbar(_("Could not open %s for writing: %s"),
name, strerror(errno));
unlink(buf);
goto cleanup_and_exit;
} else if (rename(buf, realname) == -1) {
statusbar(_("Could not open %s for writing: %s"),
realname, strerror(errno));
unlink(buf);
goto cleanup_and_exit;
}
}
if (chmod(realname, mask) == -1)
statusbar(_("Could not set permissions %o on %s: %s"),
mask, realname, strerror(errno));
if (!tmp && append == 0) {
if (!nonamechange) {
filename = mallocstrcpy(filename, realname);
#ifdef ENABLE_COLOR
update_color();
edit_refresh();
#endif
}
#ifndef NANO_SMALL
stat(filename, &originalfilestat);
#endif
statusbar(P_("Wrote %d line", "Wrote %d lines", lineswritten),
lineswritten);
UNSET(MODIFIED);
titlebar(NULL);
}
retval = 1;
cleanup_and_exit:
free(realname);
free(buf);
#ifndef NANO_SMALL
jumpok = 1;
#endif
return retval;
}
int do_writeout(const char *path, int exiting, int append)
{
int i = 0;
#ifdef NANO_EXTRA
static int did_cred = 0;
#endif
static char *writepath = NULL;
#if !defined(DISABLE_BROWSER) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
currshortcut = writefile_list;
#endif
writepath = mallocstrcpy(writepath, path);
if (exiting && ISSET(TEMP_OPT)) {
if (filename[0] != '\0') {
i = write_file(writepath, 0, 0, 0);
display_main_list();
return i;
} else {
UNSET(TEMP_OPT);
do_exit();
return -1;
}
}
while (1) {
#ifndef NANO_SMALL
const char *formatstr, *backupstr;
if (ISSET(MAC_FILE))
formatstr = _(" [Mac Format]");
else if (ISSET(DOS_FILE))
formatstr = _(" [DOS Format]");
else
formatstr = "";
if (ISSET(BACKUP_FILE))
backupstr = _(" [Backup]");
else
backupstr = "";
if (ISSET(MARK_ISSET) && !exiting) {
if (append == 2)
i = statusq(1, writefile_list, "", 0,
"%s%s%s", _("Prepend Selection to File"), formatstr, backupstr);
else if (append == 1)
i = statusq(1, writefile_list, "", 0,
"%s%s%s", _("Append Selection to File"), formatstr, backupstr);
else
i = statusq(1, writefile_list, "", 0,
"%s%s%s", _("Write Selection to File"), formatstr, backupstr);
} else {
if (append == 2)
i = statusq(1, writefile_list, writepath, 0,
"%s%s%s", _("File Name to Prepend to"), formatstr, backupstr);
else if (append == 1)
i = statusq(1, writefile_list, writepath, 0,
"%s%s%s", _("File Name to Append to"), formatstr, backupstr);
else
i = statusq(1, writefile_list, writepath, 0,
"%s%s%s", _("File Name to Write"), formatstr, backupstr);
}
#else
if (append == 2)
i = statusq(1, writefile_list, writepath,
"%s", _("File Name to Prepend to"));
else if (append == 1)
i = statusq(1, writefile_list, writepath,
"%s", _("File Name to Append to"));
else
i = statusq(1, writefile_list, writepath,
"%s", _("File Name to Write"));
#endif
if (i == -1) {
statusbar(_("Cancelled"));
display_main_list();
return 0;
}
#ifndef DISABLE_BROWSER
if (i == NANO_TOFILES_KEY) {
char *tmp = do_browse_from(answer);
currshortcut = writefile_list;
if (tmp == NULL)
continue;
free(answer);
answer = tmp;
} else
#endif
#ifndef NANO_SMALL
if (i == TOGGLE_DOS_KEY) {
UNSET(MAC_FILE);
TOGGLE(DOS_FILE);
continue;
} else if (i == TOGGLE_MAC_KEY) {
UNSET(DOS_FILE);
TOGGLE(MAC_FILE);
continue;
} else if (i == TOGGLE_BACKUP_KEY) {
TOGGLE(BACKUP_FILE);
continue;
} else
#endif
if (i == NANO_PREPEND_KEY) {
append = append == 2 ? 0 : 2;
continue;
} else if (i == NANO_APPEND_KEY) {
append = append == 1 ? 0 : 1;
continue;
}
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", answer);
#endif
#ifdef NANO_EXTRA
if (exiting && !ISSET(TEMP_OPT) && !strcasecmp(answer, "zzy")
&& !did_cred) {
do_credits();
did_cred = 1;
return -1;
}
#endif
if (append == 0 && strcmp(answer, filename) != 0) {
struct stat st;
if (!stat(answer, &st)) {
i = do_yesno(0, 0, _("File exists, OVERWRITE ?"));
if (i == 0 || i == -1)
continue;
}
}
#ifndef NANO_SMALL
if (ISSET(MARK_ISSET) && !exiting) {
filestruct *fileagebak = fileage;
filestruct *filebotbak = filebot;
filestruct *cutback = cutbuffer;
int oldmod = ISSET(MODIFIED);
cutbuffer = NULL;
cut_marked_segment(current, current_x, mark_beginbuf,
mark_beginx, 0);
fileage = cutbuffer;
filebot = get_cutbottom();
i = write_file(answer, 0, append, 1);
free_filestruct(cutbuffer);
fileage = fileagebak;
filebot = filebotbak;
cutbuffer = cutback;
if (oldmod)
set_modified();
} else
#endif
i = write_file(answer, 0, append, 0);
#ifdef ENABLE_MULTIBUFFER
if (!exiting)
add_open_file(1);
#endif
display_main_list();
return i;
}
}
int do_writeout_void(void)
{
return do_writeout(filename, 0, 0);
}
char *real_dir_from_tilde(const char *buf)
{
char *dirtmp = NULL;
if (buf[0] == '~') {
size_t i;
const struct passwd *userdata;
for (i = 1; buf[i] != '/' && buf[i] != '\0'; i++)
;
if (i == 1)
userdata = getpwuid(geteuid());
else {
do {
userdata = getpwent();
} while (userdata != NULL &&
strncmp(userdata->pw_name, buf + 1, i - 1));
}
endpwent();
if (userdata != NULL) {
dirtmp = charalloc(strlen(userdata->pw_dir) + strlen(buf + i) + 1);
sprintf(dirtmp, "%s%s", userdata->pw_dir, &buf[i]);
}
}
if (dirtmp == NULL)
dirtmp = mallocstrcpy(dirtmp, buf);
return dirtmp;
}
#ifndef DISABLE_TABCOMP
int append_slash_if_dir(char *buf, int *lastwastab, int *place)
{
char *dirptr = real_dir_from_tilde(buf);
struct stat fileinfo;
int ret = 0;
assert(dirptr != buf);
if (stat(dirptr, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode)) {
strncat(buf, "/", 1);
(*place)++;
*lastwastab = 0;
ret = 1;
}
free(dirptr);
return ret;
}
char **username_tab_completion(char *buf, int *num_matches)
{
char **matches = (char **)NULL;
char *matchline = NULL;
struct passwd *userdata;
*num_matches = 0;
matches = (char **)nmalloc(BUFSIZ * sizeof(char *));
strcat(buf, "*");
while ((userdata = getpwent()) != NULL) {
if (check_wildcard_match(userdata->pw_name, &buf[1]) == TRUE) {
#ifndef DISABLE_OPERATINGDIR
if (operating_dir != NULL) {
if (check_operating_dir(userdata->pw_dir, 1) != 0)
continue;
}
#endif
matchline = charalloc(strlen(userdata->pw_name) + 2);
sprintf(matchline, "~%s", userdata->pw_name);
matches[*num_matches] = matchline;
++*num_matches;
if (*num_matches == BUFSIZ)
break;
}
}
endpwent();
return matches;
}
char **cwd_tab_completion(char *buf, int *num_matches)
{
char *dirname, *dirtmp = NULL, *tmp = NULL, *tmp2 = NULL;
char **matches = (char **)NULL;
DIR *dir;
struct dirent *next;
matches = (char **)nmalloc(BUFSIZ * sizeof(char *));
strcat(buf, "*");
if (buf[0] != '\0' && strstr(buf, "/") != NULL) {
dirname = charalloc(strlen(buf) + 1);
tmp = buf + strlen(buf);
while (*tmp != '/' && tmp != buf)
tmp--;
tmp++;
strncpy(dirname, buf, tmp - buf + 1);
dirname[tmp - buf] = '\0';
} else {
#ifdef PATH_MAX
if ((dirname = getcwd(NULL, PATH_MAX + 1)) == NULL)
#else
if ((dirname = getcwd(NULL, 0)) == NULL)
#endif
return matches;
else
tmp = buf;
}
#ifdef DEBUG
fprintf(stderr, "\nDir = %s\n", dirname);
fprintf(stderr, "\nbuf = %s\n", buf);
fprintf(stderr, "\ntmp = %s\n", tmp);
#endif
dirtmp = real_dir_from_tilde(dirname);
free(dirname);
dirname = dirtmp;
#ifdef DEBUG
fprintf(stderr, "\nDir = %s\n", dirname);
fprintf(stderr, "\nbuf = %s\n", buf);
fprintf(stderr, "\ntmp = %s\n", tmp);
#endif
dir = opendir(dirname);
if (dir == NULL) {
*num_matches = 0;
beep();
return matches;
}
while ((next = readdir(dir)) != NULL) {
#ifdef DEBUG
fprintf(stderr, "Comparing \'%s\'\n", next->d_name);
#endif
if (check_wildcard_match(next->d_name, tmp) == TRUE) {
#ifndef DISABLE_OPERATINGDIR
if (operating_dir != NULL) {
tmp2 = charalloc(strlen(dirname) + strlen(next->d_name) + 2);
strcpy(tmp2, dirname);
strcat(tmp2, "/");
strcat(tmp2, next->d_name);
if (check_operating_dir(tmp2, 1)) {
free(tmp2);
continue;
}
free(tmp2);
}
#endif
tmp2 = NULL;
tmp2 = charalloc(strlen(next->d_name) + 1);
strcpy(tmp2, next->d_name);
matches[*num_matches] = tmp2;
++*num_matches;
if (*num_matches == BUFSIZ)
break;
}
}
closedir(dir);
free(dirname);
return matches;
}
char *input_tab(char *buf, int place, int *lastwastab, int *newplace, int *list)
{
static int num_matches = 0, match_matches = 0;
static char **matches = (char **)NULL;
int pos = place, i = 0, col = 0, editline = 0;
int longestname = 0, is_dir = 0;
char *foo;
*list = 0;
if (*lastwastab == FALSE) {
char *tmp, *copyto, *matchbuf;
*lastwastab = 1;
matchbuf = charalloc(strlen(buf) + 2);
memset(matchbuf, '\0', strlen(buf) + 2);
strncpy(matchbuf, buf, place);
tmp = matchbuf;
while (*tmp && isspace((int)*tmp))
++tmp;
if (matches != NULL) {
for (i = i; i < num_matches; i++)
free(matches[i]);
free(matches);
matches = (char **)NULL;
num_matches = 0;
}
if (buf[0] == '~' && strchr(tmp, '/') == NULL) {
buf = mallocstrcpy(buf, tmp);
matches = username_tab_completion(tmp, &num_matches);
}
else if (strlen(buf) > strlen(tmp))
buf = mallocstrcpy(buf, tmp);
if (matches == NULL)
matches = cwd_tab_completion(tmp, &num_matches);
free(matchbuf);
#ifdef DEBUG
fprintf(stderr, "%d matches found...\n", num_matches);
#endif
switch (num_matches) {
case 0:
blank_edit();
wrefresh(edit);
break;
case 1:
buf = charealloc(buf, strlen(buf) + strlen(matches[0]) + 1);
if (buf[0] != '\0' && strstr(buf, "/") != NULL) {
for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
tmp--);
tmp++;
} else
tmp = buf;
if (!strcmp(tmp, matches[0]))
is_dir = append_slash_if_dir(buf, lastwastab, newplace);
if (is_dir != 0)
break;
copyto = tmp;
for (pos = 0; *tmp == matches[0][pos] &&
pos <= strlen(matches[0]); pos++)
tmp++;
strncpy(copyto, matches[0], strlen(matches[0]) + 1);
*newplace += strlen(matches[0]) - pos;
if (*newplace < 0)
*newplace = 0;
append_slash_if_dir(buf, lastwastab, newplace);
break;
default:
if (buf[0] != '\0' && strstr(buf, "/") != NULL) {
for (tmp = buf + strlen(buf); *tmp != '/' && tmp != buf;
tmp--);
tmp++;
} else
tmp = buf;
for (pos = 0; *tmp == matches[0][pos] && *tmp != '\0' &&
pos <= strlen(matches[0]); pos++)
tmp++;
while (1) {
match_matches = 0;
for (i = 0; i < num_matches; i++) {
if (matches[i][pos] == 0)
break;
else if (matches[i][pos] == matches[0][pos])
match_matches++;
}
if (match_matches == num_matches &&
(i == num_matches || matches[i] != 0)) {
buf = charealloc(buf, strlen(buf) + 2);
strncat(buf, matches[0] + pos, 1);
*newplace += 1;
pos++;
} else {
beep();
break;
}
}
break;
}
} else {
if (matches != NULL && num_matches > 1) {
blank_edit();
wmove(edit, 0, 0);
editline = 0;
for (i = 0; i < num_matches; i++)
if (strlen(matches[i]) > longestname)
longestname = strlen(matches[i]);
if (longestname > COLS - 1)
longestname = COLS - 1;
foo = charalloc(longestname + 5);
for (i = 0, col = 0; i < num_matches; i++) {
snprintf(foo, longestname + 1, matches[i]);
while (strlen(foo) < longestname)
strcat(foo, " ");
strcat(foo, " ");
curs_set(0);
waddnstr(edit, foo, strlen(foo));
col += strlen(foo);
if (col > COLS - longestname && i + 1 < num_matches) {
editline++;
wmove(edit, editline, 0);
if (editline == editwinrows - 1) {
waddstr(edit, _("(more)"));
break;
}
col = 0;
}
}
free(foo);
wrefresh(edit);
*list = 1;
} else
beep();
}
if (*list == 0)
edit_refresh();
curs_set(1);
return buf;
}
#endif
#ifndef DISABLE_BROWSER
struct stat filestat(const char *path)
{
struct stat st;
stat(path, &st);
return st;
}
int diralphasort(const void *va, const void *vb)
{
struct stat fileinfo;
const char *a = *(char *const *)va, *b = *(char *const *)vb;
int aisdir = stat(a, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode);
int bisdir = stat(b, &fileinfo) != -1 && S_ISDIR(fileinfo.st_mode);
if (aisdir != 0 && bisdir == 0)
return -1;
if (aisdir == 0 && bisdir != 0)
return 1;
return strcasecmp(a, b);
}
void free_charptrarray(char **array, int len)
{
for (; len > 0; len--)
free(array[len - 1]);
free(array);
}
const char *tail(const char *foo)
{
const char *tmp = foo + strlen(foo);
while (*tmp != '/' && tmp != foo)
tmp--;
if (*tmp == '/')
tmp++;
return tmp;
}
void striponedir(char *foo)
{
char *tmp;
assert(foo != NULL);
if (*foo == '\0' || strcmp(foo, "/") == 0)
return;
tmp = foo + strlen(foo) - 1;
assert(tmp >= foo);
if (*tmp == '/')
*tmp = '\0';
while (*tmp != '/' && tmp != foo)
tmp--;
if (tmp != foo)
*tmp = '\0';
else {
if (*tmp != '/')
*tmp = '.';
*(tmp + 1) = '\0';
}
}
int readable_dir(const char *path)
{
DIR *dir = opendir(path);
if (dir != NULL)
closedir(dir);
return dir != NULL;
}
char **browser_init(const char *path, int *longest, int *numents)
{
DIR *dir;
struct dirent *next;
char **filelist;
int i = 0;
size_t path_len;
dir = opendir(path);
if (dir == NULL)
return NULL;
*numents = 0;
while ((next = readdir(dir)) != NULL) {
if (!strcmp(next->d_name, "."))
continue;
(*numents)++;
if (strlen(next->d_name) > *longest)
*longest = strlen(next->d_name);
}
rewinddir(dir);
*longest += 10;
filelist = (char **)nmalloc(*numents * sizeof (char *));
if (!strcmp(path, "/"))
path = "";
path_len = strlen(path);
while ((next = readdir(dir)) != NULL) {
if (!strcmp(next->d_name, "."))
continue;
filelist[i] = charalloc(strlen(next->d_name) + path_len + 2);
sprintf(filelist[i], "%s/%s", path, next->d_name);
i++;
}
closedir(dir);
if (*longest > COLS - 1)
*longest = COLS - 1;
return filelist;
}
char *do_browser(const char *inpath)
{
struct stat st;
char *foo, *retval = NULL;
static char *path = NULL;
int numents = 0, i = 0, j = 0, kbinput = 0, longest = 0, abort = 0;
int col = 0, selected = 0, editline = 0, width = 0, filecols = 0;
int lineno = 0, kb;
char **filelist = (char **)NULL;
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
MEVENT mevent;
#endif
assert(inpath != NULL);
if (path != NULL && strcmp(path, inpath)) {
free(path);
path = NULL;
}
if (path == NULL)
path = mallocstrcpy(NULL, inpath);
filelist = browser_init(path, &longest, &numents);
foo = charalloc(longest + 8);
qsort(filelist, numents, sizeof(char *), diralphasort);
kb = keypad_on(edit, 1);
titlebar(path);
bottombars(browser_list);
curs_set(0);
wmove(edit, 0, 0);
i = 0;
width = 0;
filecols = 0;
do {
char *new_path;
blank_statusbar_refresh();
#if !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
currshortcut = browser_list;
#endif
editline = 0;
col = 0;
lineno = selected;
if (width != 0)
lineno /= width;
switch (kbinput) {
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
case KEY_MOUSE:
if (getmouse(&mevent) == ERR)
return retval;
if (wenclose(edit, mevent.y, mevent.x)) {
int selectedbackup = selected;
mevent.y -= 2;
selected = (lineno / editwinrows) * editwinrows * width
+ mevent.y * width + mevent.x / (longest + 2);
if (mevent.x > width * (longest + 2))
selected--;
if (selected > numents - 1)
selected = numents - 1;
else if (selectedbackup == selected)
ungetch('s');
} else
do_mouse();
break;
#endif
case NANO_UP_KEY:
case KEY_UP:
if (selected - width >= 0)
selected -= width;
break;
case NANO_BACK_KEY:
case KEY_LEFT:
if (selected > 0)
selected--;
break;
case KEY_DOWN:
case NANO_DOWN_KEY:
if (selected + width <= numents - 1)
selected += width;
break;
case KEY_RIGHT:
case NANO_FORWARD_KEY:
if (selected < numents - 1)
selected++;
break;
case NANO_PREVPAGE_KEY:
case NANO_PREVPAGE_FKEY:
case KEY_PPAGE:
case '-':
if (selected >= (editwinrows + lineno % editwinrows) * width)
selected -= (editwinrows + lineno % editwinrows) * width;
else
selected = 0;
break;
case NANO_NEXTPAGE_KEY:
case NANO_NEXTPAGE_FKEY:
case KEY_NPAGE:
case ' ':
selected += (editwinrows - lineno % editwinrows) * width;
if (selected >= numents)
selected = numents - 1;
break;
case NANO_HELP_KEY:
case NANO_HELP_FKEY:
case '?':
do_help();
break;
case KEY_ENTER:
case NANO_ENTER_KEY:
case 'S':
case 's':
if (!strcmp(filelist[selected], "/..") && !strcmp(path, "/")) {
statusbar(_("Can't move up a directory"));
beep();
break;
}
#ifndef DISABLE_OPERATINGDIR
if (check_operating_dir(filelist[selected], FALSE)) {
statusbar(_("Can't go outside of %s in restricted mode"), operating_dir);
beep();
break;
}
#endif
if (stat(filelist[selected], &st) == -1) {
statusbar(_("Can't open \"%s\": %s"), filelist[selected], strerror(errno));
beep();
break;
}
if (!S_ISDIR(st.st_mode)) {
retval = mallocstrcpy(retval, filelist[selected]);
abort = 1;
break;
}
new_path = mallocstrcpy(NULL, filelist[selected]);
if (strcmp("..", tail(new_path)) == 0) {
striponedir(new_path);
if (strcmp(new_path, ".") == 0) {
free(new_path);
new_path = getcwd(NULL, PATH_MAX + 1);
}
striponedir(new_path);
}
if (!readable_dir(new_path)) {
statusbar(_("Can't open \"%s\": %s"), new_path, strerror(errno));
free(new_path);
break;
}
free_charptrarray(filelist, numents);
free(foo);
free(path);
path = new_path;
return do_browser(path);
case 'g':
case 'G':
case NANO_GOTO_KEY:
curs_set(1);
j = statusq(0, gotodir_list, "",
#ifndef NANO_SMALL
0,
#endif
_("Goto Directory"));
bottombars(browser_list);
curs_set(0);
if (j < 0) {
statusbar(_("Goto Cancelled"));
break;
}
new_path = real_dir_from_tilde(answer);
if (new_path[0] != '/') {
new_path = charealloc(new_path, strlen(path) + strlen(answer) + 2);
sprintf(new_path, "%s/%s", path, answer);
}
#ifndef DISABLE_OPERATINGDIR
if (check_operating_dir(new_path, FALSE)) {
statusbar(_("Can't go outside of %s in restricted mode"), operating_dir);
free(new_path);
break;
}
#endif
if (!readable_dir(new_path)) {
statusbar(_("Can't open \"%s\": %s"), answer, strerror(errno));
free(new_path);
break;
}
free_charptrarray(filelist, numents);
free(foo);
free(path);
path = new_path;
return do_browser(path);
case 'q':
case 'Q':
case 'e':
case 'E':
case NANO_CANCEL_KEY:
case NANO_EXIT_FKEY:
abort = 1;
break;
}
if (abort)
break;
blank_edit();
if (width != 0)
i = width * editwinrows * ((selected / width) / editwinrows);
else
i = 0;
wmove(edit, 0, 0);
for (j = i; j < numents && editline <= editwinrows - 1; j++) {
filecols++;
strncpy(foo, tail(filelist[j]), strlen(tail(filelist[j])) + 1);
while (strlen(foo) < longest)
strcat(foo, " ");
col += strlen(foo);
lstat(filelist[j], &st);
if (S_ISDIR(st.st_mode))
strcpy(foo + longest - 5, "(dir)");
else {
if (S_ISLNK(st.st_mode)) {
st = filestat(filelist[j]);
if (S_ISDIR(st.st_mode))
strcpy(foo + longest - 5, "(dir)");
else
strcpy(foo + longest - 2, "--");
} else if (st.st_size < (1 << 10))
sprintf(foo + longest - 7, "%4d B",
(int) st.st_size);
else if (st.st_size >= (1 << 30))
sprintf(foo + longest - 7, "%4d GB",
(int) st.st_size >> 30);
else if (st.st_size >= (1 << 20))
sprintf(foo + longest - 7, "%4d MB",
(int) st.st_size >> 20);
else
sprintf(foo + longest - 7, "%4d KB",
(int) st.st_size >> 10);
}
if (j == selected)
wattron(edit, A_REVERSE);
waddstr(edit, foo);
if (j == selected)
wattroff(edit, A_REVERSE);
waddstr(edit, " ");
col += 2;
if (col > COLS - longest) {
editline++;
wmove(edit, editline, 0);
col = 0;
if (width == 0)
width = filecols;
}
}
wrefresh(edit);
} while ((kbinput = wgetch(edit)) != NANO_EXIT_KEY);
curs_set(1);
blank_edit();
titlebar(NULL);
edit_refresh();
kb = keypad_on(edit, kb);
free_charptrarray(filelist, numents);
free(foo);
return retval;
}
char *do_browse_from(const char *inpath)
{
struct stat st;
char *bob;
char *path;
assert(inpath != NULL);
path = real_dir_from_tilde(inpath);
if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
striponedir(path);
if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
free(path);
path = getcwd(NULL, PATH_MAX + 1);
}
}
#ifndef DISABLE_OPERATINGDIR
if (check_operating_dir(path, FALSE))
path = mallocstrcpy(path, operating_dir);
#endif
if (!readable_dir(path)) {
beep();
bob = NULL;
} else
bob = do_browser(path);
free(path);
return bob;
}
#endif
#ifndef NANO_SMALL
#ifdef ENABLE_NANORC
void load_history(void)
{
FILE *hist;
const struct passwd *userage = NULL;
static char *nanohist;
char *buf, *ptr;
char *homenv = getenv("HOME");
historyheadtype *history = &search_history;
if (homenv != NULL) {
nanohist = charealloc(nanohist, strlen(homenv) + 15);
sprintf(nanohist, "%s/.nano_history", homenv);
} else {
userage = getpwuid(geteuid());
endpwent();
nanohist = charealloc(nanohist, strlen(userage->pw_dir) + 15);
sprintf(nanohist, "%s/.nano_history", userage->pw_dir);
}
if (homenv != NULL || userage != NULL) {
hist = fopen(nanohist, "r");
if (!hist) {
if (errno != ENOENT) {
UNSET(HISTORYLOG);
rcfile_error(_("Unable to open ~/.nano_history file, %s"), strerror(errno));
}
free(nanohist);
} else {
buf = charalloc(1024);
while (fgets(buf, 1023, hist) != 0) {
ptr = buf;
while (*ptr != '\n' && *ptr != '\0' && ptr < buf + 1023)
ptr++;
*ptr = '\0';
if (strlen(buf))
update_history(history, buf);
else
history = &replace_history;
}
fclose(hist);
free(buf);
free(nanohist);
UNSET(HISTORY_CHANGED);
}
}
}
void save_history(void)
{
FILE *hist;
const struct passwd *userage = NULL;
char *nanohist = NULL;
char *homenv = getenv("HOME");
historytype *h;
if (!((search_history.count || replace_history.count) &&
ISSET(HISTORY_CHANGED) && !ISSET(VIEW_MODE)))
return;
if (homenv != NULL) {
nanohist = charealloc(nanohist, strlen(homenv) + 15);
sprintf(nanohist, "%s/.nano_history", homenv);
} else {
userage = getpwuid(geteuid());
endpwent();
nanohist = charealloc(nanohist, strlen(userage->pw_dir) + 15);
sprintf(nanohist, "%s/.nano_history", userage->pw_dir);
}
if (homenv != NULL || userage != NULL) {
hist = fopen(nanohist, "wb");
if (!hist) {
rcfile_msg(_("Unable to write ~/.nano_history file, %s"), strerror(errno));
} else {
chmod(nanohist, S_IRUSR | S_IWUSR);
for (h = search_history.tail ; h->prev ; h = h->prev) {
h->data = charealloc(h->data, strlen(h->data) + 2);
strcat(h->data, "\n");
if (fputs(h->data, hist) == EOF) {
rcfile_msg(_("Unable to write ~/.nano_history file, %s"), strerror(errno));
goto come_from;
}
}
if (fputs("\n", hist) == EOF) {
rcfile_msg(_("Unable to write ~/.nano_history file, %s"), strerror(errno));
goto come_from;
}
for (h = replace_history.tail ; h->prev ; h = h->prev) {
h->data = charealloc(h->data, strlen(h->data) + 2);
strcat(h->data, "\n");
if (fputs(h->data, hist) == EOF) {
rcfile_msg(_("Unable to write ~/.nano_history file, %s"), strerror(errno));
goto come_from;
}
}
come_from:
fclose(hist);
}
free(nanohist);
}
}
#endif
#endif