CVS code -
- General:
- - More int -> bool conversions. (DLR)
+ - More int -> bool conversions. (DLR and David Benbennick)
- Overhaul the cutting and uncutting routines to use the
partitioning code, as it greatly simplifies how they work.
New functions move_to_filestruct(), copy_from_filestruct(),
- Overhaul the tab completion code and a few related functions
to increase efficiency and support multibyte characters. New
functions strrchrn() and is_dir(); changes to get_full_path(),
- check_writable_directory(), diralphasort(),
+ check_writable_directory(), safe_tempnam(), diralphasort(),
username_tab_completion(), cwd_tab_completion(), input_tab(),
tail(), and striponedir(); removal of append_slash_if_dir()
and check_wildcard_match(). (David Benbennick) DLR: Move the
/* Parse a multibyte character from buf. Return the number of bytes
* used. If chr isn't NULL, store the multibyte character in it. If
- * bad_chr isn't NULL, set it to TRUE if we have a null byte or a bad
- * multibyte character. If col isn't NULL, store the new display width
- * in it. If *str is '\t', we expect col to have the current display
- * width. */
-int parse_mbchar(const char *buf, char *chr
-#ifdef NANO_WIDE
- , bool *bad_chr
-#endif
- , size_t *col)
+ * bad_chr isn't NULL, set it to TRUE if we have a bad multibyte
+ * character. If col isn't NULL, store the new display width in it. If
+ * *str is '\t', we expect col to have the current display width. */
+int parse_mbchar(const char *buf, char *chr, bool *bad_chr, size_t
+ *col)
{
int buf_mb_len;
assert(buf != NULL);
-#ifdef NANO_WIDE
if (bad_chr != NULL)
*bad_chr = FALSE;
+#ifdef NANO_WIDE
if (!ISSET(NO_UTF8)) {
/* Get the number of bytes in the multibyte character. */
buf_mb_len = mblen(buf, MB_CUR_MAX);
/* If buf contains a null byte or an invalid multibyte
- * character, interpret buf's first byte and set bad_chr to
- * TRUE. */
+ * character, set bad_chr to TRUE (if it contains the latter)
+ * and interpret buf's first byte. */
if (buf_mb_len <= 0) {
mblen(NULL, 0);
- buf_mb_len = 1;
- if (bad_chr != NULL)
+ if (buf_mb_len < 0 && bad_chr != NULL)
*bad_chr = TRUE;
+ buf_mb_len = 1;
}
/* Save the multibyte character in chr. */
/* There is no library function to move backward one multibyte
* character. Here is the naive, O(pos) way to do it. */
while (TRUE) {
- int buf_mb_len = parse_mbchar(buf + pos - pos_prev, NULL
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ int buf_mb_len = parse_mbchar(buf + pos - pos_prev, NULL, NULL,
+ NULL);
if (pos_prev <= (size_t)buf_mb_len)
break;
* after the one at pos. */
size_t move_mbright(const char *buf, size_t pos)
{
- return pos + parse_mbchar(buf + pos, NULL
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ return pos + parse_mbchar(buf + pos, NULL, NULL, NULL);
}
#ifndef HAVE_STRCASECMP
return full_path;
}
-/*
- * This function accepts a directory name and filename prefix the same
- * way that tempnam() does, determines the location for its temporary
- * file the same way that tempnam() does, safely creates the temporary
- * file there via mkstemp(), and returns the name of the temporary file
- * the same way that tempnam() does. It does not reference the value of
- * TMP_MAX because the total number of random filenames that it can
- * generate using one prefix is equal to 256**6, which is a sufficiently
- * large number to handle most cases. Since the behavior after tempnam()
- * generates TMP_MAX random filenames is implementation-defined, my
- * implementation is to go on generating random filenames regardless of
- * it.
- */
-char *safe_tempnam(const char *dirname, const char *filename_prefix)
+/* This function acts like a call to tempnam(NULL, "nano."). The
+ * difference is that the number of calls is not limited by TMP_MAX.
+ * Instead we use mkstemp(). */
+char *safe_tempnam(void)
{
char *full_tempdir = NULL;
const char *TMPDIR_env;
int filedesc;
- /* if $TMPDIR is set and non-empty, set tempdir to it, run it through
- get_full_path(), and save the result in full_tempdir; otherwise,
- leave full_tempdir set to NULL */
+ /* If $TMPDIR is set and non-empty, set tempdir to it, run it
+ * through get_full_path(), and save the result in full_tempdir.
+ * Otherwise, leave full_tempdir set to NULL. */
TMPDIR_env = getenv("TMPDIR");
if (TMPDIR_env != NULL && TMPDIR_env[0] != '\0')
full_tempdir = check_writable_directory(TMPDIR_env);
- /* if $TMPDIR is blank or isn't set, or isn't a writable
- directory, and dirname isn't NULL, try it; otherwise, leave
- full_tempdir set to NULL */
- if (full_tempdir == NULL && dirname != NULL)
- full_tempdir = check_writable_directory(dirname);
-
- /* if $TMPDIR is blank or isn't set, or if it isn't a writable
- directory, and dirname is NULL, try P_tmpdir instead */
+ /* If $TMPDIR is unset, empty, or not a writable directory, and
+ * full_tempdir is NULL, try P_tmpdir instead. */
if (full_tempdir == NULL)
full_tempdir = check_writable_directory(P_tmpdir);
- /* if P_tmpdir didn't work, use /tmp instead */
- if (full_tempdir == NULL) {
- full_tempdir = charalloc(6);
- strcpy(full_tempdir, "/tmp/");
- }
+ /* if P_tmpdir is NULL, use /tmp. */
+ if (full_tempdir == NULL)
+ full_tempdir = mallocstrcpy(NULL, "/tmp/");
full_tempdir = charealloc(full_tempdir, strlen(full_tempdir) + 12);
-
- /* like tempnam(), use only the first 5 characters of the prefix */
- strncat(full_tempdir, filename_prefix, 5);
- strcat(full_tempdir, "XXXXXX");
+ strcat(full_tempdir, "nano.XXXXXX");
filedesc = mkstemp(full_tempdir);
- /* if mkstemp succeeded, close the resulting file; afterwards, it'll be
- 0 bytes long, so delete it; finally, return the filename (all that's
- left of it) */
+ /* If mkstemp() succeeded, close the resulting file, delete it
+ * (since it'll be 0 bytes long), and return the filename. */
if (filedesc != -1) {
close(filedesc);
unlink(full_tempdir);
}
free(full_tempdir);
+
return NULL;
}
#endif /* !DISABLE_SPELLER */
}
}
-/* Check to see if we're inside the operating directory. Return 0 if we
- * are, or 1 otherwise. If allow_tabcomp is nonzero, allow incomplete
- * names that would be matches for the operating directory, so that tab
- * completion will work. */
-int check_operating_dir(const char *currpath, bool allow_tabcomp)
+/* Check to see if we're inside the operating directory. Return FALSE
+ * if we are, or TRUE otherwise. If allow_tabcomp is TRUE, allow
+ * incomplete names that would be matches for the operating directory,
+ * so that tab completion will work. */
+bool check_operating_dir(const char *currpath, bool allow_tabcomp)
{
/* The char *full_operating_dir is global for mem cleanup. It
* should have already been initialized by init_operating_dir().
* properly if this is done. */
char *fullpath;
- int retval = 0;
+ bool retval = FALSE;
const char *whereami1, *whereami2 = NULL;
/* If no operating directory is set, don't bother doing anything. */
if (operating_dir == NULL)
- return 0;
+ return FALSE;
assert(full_operating_dir != NULL);
fullpath = get_full_path(currpath);
/* fullpath == NULL means some directory in the path doesn't exist
- * or is unreadable. If allow_tabcomp is zero, then currpath is
+ * or is unreadable. If allow_tabcomp is FALSE, then currpath is
* what the user typed somewhere. We don't want to report a
* non-existent directory as being outside the operating directory,
- * so we return 0. If allow_tabcomp is nonzero, then currpath
+ * so we return FALSE. If allow_tabcomp is TRUE, then currpath
* exists, but is not executable. So we say it isn't in the
* operating directory. */
if (fullpath == NULL)
* (for normal usage) and vice versa (for tab completion, if we're
* allowing it), we're outside the operating directory. */
if (whereami1 != fullpath && whereami2 != full_operating_dir)
- retval = 1;
- free(fullpath);
+ retval = TRUE;
+ free(fullpath);
/* Otherwise, we're still inside it. */
return retval;
#ifndef DISABLE_OPERATINGDIR
/* If we're writing a temporary file, we're probably going outside
* the operating directory, so skip the operating directory test. */
- if (!tmp && check_operating_dir(realname, FALSE) != 0) {
+ if (!tmp && check_operating_dir(realname, FALSE)) {
statusbar(_("Can't write outside of %s"), operating_dir);
goto cleanup_and_exit;
}
/* Note: the selected file can be outside the operating
* directory if it is .. or if it is a symlink to
* directory outside the operating directory. */
- if (check_operating_dir(filelist[selected], FALSE) != 0) {
+ if (check_operating_dir(filelist[selected], FALSE)) {
statusbar(_("Can't go outside of %s in restricted mode"),
operating_dir);
beep();
}
#ifndef DISABLE_OPERATINGDIR
- if (check_operating_dir(new_path, FALSE) != 0) {
+ if (check_operating_dir(new_path, FALSE)) {
statusbar(_("Can't go outside of %s in restricted mode"), operating_dir);
free(new_path);
break;
#ifndef DISABLE_OPERATINGDIR
/* If the resulting path isn't in the operating directory, use that. */
- if (check_operating_dir(path, FALSE) != 0)
+ if (check_operating_dir(path, FALSE))
path = mallocstrcpy(path, operating_dir);
#endif
placewewant = xplustabs();
if (current->data[current_x] != '\0') {
- int char_buf_len = parse_mbchar(current->data + current_x, NULL
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ int char_buf_len = parse_mbchar(current->data + current_x, NULL,
+ NULL, NULL);
size_t line_len = strlen(current->data + current_x);
assert(current_x < strlen(current->data));
/* Move forward until we find the character after the last letter of
* the current word. */
while (current->data[current_x] != '\0') {
- char_mb_len = parse_mbchar(current->data + current_x, char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb_len = parse_mbchar(current->data + current_x, char_mb,
+ NULL, NULL);
/* If we've found it, stop moving forward through the current
* line. */
for (; current != NULL; current = current->next) {
while (current->data[current_x] != '\0') {
char_mb_len = parse_mbchar(current->data + current_x,
- char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb, NULL, NULL);
/* If we've found it, stop moving forward through the
* current line. */
/* Move backward until we find the character before the first letter
* of the current word. */
while (!begin_line) {
- char_mb_len = parse_mbchar(current->data + current_x, char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb_len = parse_mbchar(current->data + current_x, char_mb,
+ NULL, NULL);
/* If we've found it, stop moving backward through the current
* line. */
for (; current != NULL; current = current->prev) {
while (!begin_line) {
char_mb_len = parse_mbchar(current->data + current_x,
- char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb, NULL, NULL);
/* If we've found it, stop moving backward through the
* current line. */
while (!begin_line) {
char_mb_len = parse_mbchar(current->data + current_x,
- char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb, NULL, NULL);
/* If we've found it, stop moving backward through the
* current line. */
void do_spell(void)
{
int i;
- char *temp = safe_tempnam(0, "nano.");
+ char *temp = safe_tempnam();
const char *spell_msg;
if (temp == NULL) {
blank_mb = charalloc(mb_cur_max());
while (*line != '\0') {
- blank_mb_len = parse_mbchar(line, blank_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ blank_mb_len = parse_mbchar(line, blank_mb, NULL, NULL);
if (!is_blank_mbchar(blank_mb))
break;
if (is_blank_char(*line))
return TRUE;
- line += parse_mbchar(line, NULL
-#ifdef NANO_WIDE
- , NULL
-#endif
- , &pos);
+ line += parse_mbchar(line, NULL, NULL, &pos);
goal -= pos;
}
assert(*line != '\t');
- line_len = parse_mbchar(line, NULL
-#ifdef NANO_WIDE
- , NULL
-#endif
- , &pos);
+ line_len = parse_mbchar(line, NULL, NULL, &pos);
goal -= pos;
line += line_len;
/* Interpret the next multibyte character. If it's an invalid
* multibyte character, interpret it as though it's a byte
* character. */
- char_buf_len = parse_mbchar(output + i, char_buf
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_buf_len = parse_mbchar(output + i, char_buf, NULL, NULL);
i += char_buf_len;
int mbwidth(const char *c);
int mb_cur_max(void);
char *make_mbchar(int chr, char *chr_mb, int *chr_mb_len);
-int parse_mbchar(const char *buf, char *chr
-#ifdef NANO_WIDE
- , bool *bad_chr
-#endif
- , size_t *col);
+int parse_mbchar(const char *buf, char *chr, bool *bad_chr, size_t
+ *col);
size_t move_mbleft(const char *buf, size_t pos);
size_t move_mbright(const char *buf, size_t pos);
#ifndef HAVE_STRCASECMP
#endif
#ifndef DISABLE_SPELLER
char *check_writable_directory(const char *path);
-char *safe_tempnam(const char *dirname, const char *filename_prefix);
+char *safe_tempnam(void);
#endif
#ifndef DISABLE_OPERATINGDIR
void init_operating_dir(void);
-int check_operating_dir(const char *currpath, bool allow_tabcomp);
+bool check_operating_dir(const char *currpath, bool allow_tabcomp);
#endif
#ifndef NANO_SMALL
void init_backup_dir(void);
void do_statusbar_delete(void)
{
if (statusbar_x < statusbar_xend) {
- int char_buf_len = parse_mbchar(answer + statusbar_x, NULL
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ int char_buf_len = parse_mbchar(answer + statusbar_x, NULL,
+ NULL, NULL);
charmove(answer + statusbar_x, answer + statusbar_x +
char_buf_len, statusbar_xend - statusbar_x -
/* Move forward until we find the character after the last letter of
* the current word. */
while (statusbar_x < statusbar_xend) {
- char_mb_len = parse_mbchar(answer + statusbar_x, char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL,
+ NULL);
/* If we've found it, stop moving forward through the current
* line. */
current_x += char_mb_len;
while (statusbar_x < statusbar_xend) {
- char_mb_len = parse_mbchar(answer + statusbar_x, char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL,
+ NULL);
/* If we've found it, stop moving forward through the current
* line. */
/* Move backward until we find the character before the first letter
* of the current word. */
while (!begin_line) {
- char_mb_len = parse_mbchar(answer + statusbar_x, char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL,
+ NULL);
/* If we've found it, stop moving backward through the current
* line. */
statusbar_x = move_mbleft(answer, statusbar_x);
while (!begin_line) {
- char_mb_len = parse_mbchar(answer + statusbar_x, char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL,
+ NULL);
/* If we've found it, stop moving backward through the current
* line. */
statusbar_x = move_mbleft(answer, statusbar_x);
while (!begin_line) {
- char_mb_len = parse_mbchar(answer + statusbar_x, char_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_mb_len = parse_mbchar(answer + statusbar_x, char_mb,
+ NULL, NULL);
/* If we've found it, stop moving backward through the
* current line. */
/* Interpret the next multibyte character. If it's an invalid
* multibyte character, interpret it as though it's a byte
* character. */
- char_buf_len = parse_mbchar(output + i, char_buf
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ char_buf_len = parse_mbchar(output + i, char_buf, NULL, NULL);
i += char_buf_len;
assert(str != NULL);
while (*str != '\0') {
- int str_len = parse_mbchar(str, NULL
-#ifdef NANO_WIDE
- , NULL
-#endif
- , &length);
+ int str_len = parse_mbchar(str, NULL, NULL, &length);
if (length > xplus)
break;
assert(str != NULL);
while (*str != '\0') {
- int str_len = parse_mbchar(str, NULL
-#ifdef NANO_WIDE
- , NULL
-#endif
- , &length);
+ int str_len = parse_mbchar(str, NULL, NULL, &length);
str += str_len;
buf[start_index] != '\t')) {
/* We don't display all of buf[start_index] since it starts to
* the left of the screen. */
- buf_mb_len = parse_mbchar(buf + start_index, buf_mb
-#ifdef NANO_WIDE
- , NULL
-#endif
- , NULL);
+ buf_mb_len = parse_mbchar(buf + start_index, buf_mb, NULL,
+ NULL);
if (is_cntrl_mbchar(buf_mb)) {
if (column < start_col) {
buf_mb_len = parse_mbchar(buf + start_index, buf_mb
#ifdef NANO_WIDE
, &bad_char
+#else
+ , NULL
#endif
, NULL);