2011-10-15 14:56:47 +04:00
|
|
|
/*
|
|
|
|
Various utilities
|
|
|
|
|
2007-09-25 19:33:35 +04:00
|
|
|
Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
|
2011-10-15 14:56:47 +04:00
|
|
|
2004, 2005, 2007, 2009, 2011
|
|
|
|
The Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Written by:
|
|
|
|
Miguel de Icaza, 1994, 1995, 1996
|
|
|
|
Janne Kukonlehto, 1994, 1995, 1996
|
|
|
|
Dugan Porter, 1994, 1995, 1996
|
|
|
|
Jakub Jelinek, 1994, 1995, 1996
|
|
|
|
Mauricio Plaza, 1994, 1995, 1996
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
The file_date routine is mostly from GNU's fileutils package,
|
|
|
|
written by Richard Stallman and David MacKenzie.
|
|
|
|
|
2011-10-15 14:56:47 +04:00
|
|
|
This file is part of the Midnight Commander.
|
2010-02-26 12:25:53 +03:00
|
|
|
|
2011-10-15 14:56:47 +04:00
|
|
|
The Midnight Commander is free software: you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation, either version 3 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
The Midnight Commander is distributed in the hope that it will be useful,
|
1998-02-27 07:54:42 +03:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
2011-10-15 14:56:47 +04:00
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-02-06 17:46:15 +03:00
|
|
|
/** \file
|
2009-02-05 21:28:18 +03:00
|
|
|
* \brief Source: various utilities
|
|
|
|
*/
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <config.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <stdarg.h>
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <stdio.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2009-02-06 02:30:45 +03:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/time.h>
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
#include <unistd.h>
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-01-20 18:11:52 +03:00
|
|
|
#include "lib/global.h"
|
2010-01-21 16:06:15 +03:00
|
|
|
#include "lib/mcconfig.h"
|
2010-01-21 13:30:08 +03:00
|
|
|
#include "lib/fileloc.h"
|
2011-02-15 16:44:17 +03:00
|
|
|
#include "lib/vfs/vfs.h"
|
2010-01-21 15:17:26 +03:00
|
|
|
#include "lib/strutil.h"
|
2010-11-11 16:58:29 +03:00
|
|
|
#include "lib/util.h"
|
2001-06-06 02:49:15 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/*** global variables ****************************************************************************/
|
|
|
|
|
|
|
|
/*** file scope macro definitions ****************************************************************/
|
|
|
|
|
|
|
|
#define ismode(n,m) ((n & m) == m)
|
|
|
|
|
|
|
|
/* Number of attempts to create a temporary file */
|
|
|
|
#ifndef TMP_MAX
|
|
|
|
#define TMP_MAX 16384
|
|
|
|
#endif /* !TMP_MAX */
|
|
|
|
|
|
|
|
#define TMP_SUFFIX ".tmp"
|
|
|
|
|
|
|
|
#define ASCII_A (0x40 + 1)
|
|
|
|
#define ASCII_Z (0x40 + 26)
|
|
|
|
#define ASCII_a (0x60 + 1)
|
|
|
|
#define ASCII_z (0x60 + 26)
|
|
|
|
|
|
|
|
/*** file scope type declarations ****************************************************************/
|
|
|
|
|
|
|
|
/*** file scope variables ************************************************************************/
|
|
|
|
|
|
|
|
/*** file scope functions ************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2004-08-19 15:26:48 +04:00
|
|
|
|
2002-09-22 11:40:56 +04:00
|
|
|
static inline int
|
|
|
|
is_7bit_printable (unsigned char c)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2002-09-22 11:40:56 +04:00
|
|
|
return (c > 31 && c < 127);
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2002-09-22 11:40:56 +04:00
|
|
|
static inline int
|
|
|
|
is_iso_printable (unsigned char c)
|
|
|
|
{
|
|
|
|
return ((c > 31 && c < 127) || c >= 160);
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2002-09-22 11:40:56 +04:00
|
|
|
static inline int
|
|
|
|
is_8bit_printable (unsigned char c)
|
|
|
|
{
|
|
|
|
/* "Full 8 bits output" doesn't work on xterm */
|
2011-09-06 14:35:42 +04:00
|
|
|
if (mc_global.tty.xterm_flag)
|
2010-02-26 12:25:53 +03:00
|
|
|
return is_iso_printable (c);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2002-09-22 11:40:56 +04:00
|
|
|
return (c > 31 && c != 127 && c != 155);
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static char *
|
|
|
|
resolve_symlinks (const char *path)
|
|
|
|
{
|
|
|
|
char *buf, *buf2, *q, *r, c;
|
|
|
|
int len;
|
|
|
|
struct stat mybuf;
|
|
|
|
const char *p;
|
2011-07-18 01:30:58 +04:00
|
|
|
vfs_path_t *vpath;
|
2010-11-08 13:21:45 +03:00
|
|
|
|
|
|
|
if (*path != PATH_SEP)
|
|
|
|
return NULL;
|
2011-07-18 01:30:58 +04:00
|
|
|
|
|
|
|
vpath = vfs_path_from_str (path);
|
2010-11-08 13:21:45 +03:00
|
|
|
r = buf = g_malloc (MC_MAXPATHLEN);
|
|
|
|
buf2 = g_malloc (MC_MAXPATHLEN);
|
|
|
|
*r++ = PATH_SEP;
|
|
|
|
*r = 0;
|
|
|
|
p = path;
|
2011-07-18 01:30:58 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
q = strchr (p + 1, PATH_SEP);
|
|
|
|
if (!q)
|
|
|
|
{
|
|
|
|
q = strchr (p + 1, 0);
|
|
|
|
if (q == p + 1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
c = *q;
|
|
|
|
*q = 0;
|
2011-07-18 01:30:58 +04:00
|
|
|
if (mc_lstat (vpath, &mybuf) < 0)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
|
|
|
g_free (buf);
|
2011-07-18 01:30:58 +04:00
|
|
|
buf = NULL;
|
2010-11-08 13:21:45 +03:00
|
|
|
*q = c;
|
2011-07-18 01:30:58 +04:00
|
|
|
goto ret;
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
if (!S_ISLNK (mybuf.st_mode))
|
|
|
|
strcpy (r, p + 1);
|
|
|
|
else
|
|
|
|
{
|
2011-07-21 01:22:50 +04:00
|
|
|
len = mc_readlink (vpath, buf2, MC_MAXPATHLEN - 1);
|
2010-11-08 13:21:45 +03:00
|
|
|
if (len < 0)
|
|
|
|
{
|
|
|
|
g_free (buf);
|
2011-07-18 01:30:58 +04:00
|
|
|
buf = NULL;
|
2010-11-08 13:21:45 +03:00
|
|
|
*q = c;
|
2011-07-18 01:30:58 +04:00
|
|
|
goto ret;
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
buf2[len] = 0;
|
|
|
|
if (*buf2 == PATH_SEP)
|
|
|
|
strcpy (buf, buf2);
|
|
|
|
else
|
|
|
|
strcpy (r, buf2);
|
|
|
|
}
|
|
|
|
canonicalize_pathname (buf);
|
|
|
|
r = strchr (buf, 0);
|
|
|
|
if (!*r || *(r - 1) != PATH_SEP)
|
|
|
|
{
|
|
|
|
*r++ = PATH_SEP;
|
|
|
|
*r = 0;
|
|
|
|
}
|
|
|
|
*q = c;
|
|
|
|
p = q;
|
|
|
|
if (!c)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!*buf)
|
|
|
|
strcpy (buf, PATH_SEP_STR);
|
|
|
|
else if (*(r - 1) == PATH_SEP && r != buf + 1)
|
|
|
|
*(r - 1) = 0;
|
2011-07-18 01:30:58 +04:00
|
|
|
|
|
|
|
ret:
|
2010-11-08 13:21:45 +03:00
|
|
|
g_free (buf2);
|
2011-07-18 01:30:58 +04:00
|
|
|
vfs_path_free (vpath);
|
2010-11-08 13:21:45 +03:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
mc_util_write_backup_content (const char *from_file_name, const char *to_file_name)
|
|
|
|
{
|
|
|
|
FILE *backup_fd;
|
|
|
|
char *contents;
|
|
|
|
gsize length;
|
|
|
|
gboolean ret1 = TRUE;
|
|
|
|
|
|
|
|
if (!g_file_get_contents (from_file_name, &contents, &length, NULL))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
backup_fd = fopen (to_file_name, "w");
|
|
|
|
if (backup_fd == NULL)
|
|
|
|
{
|
|
|
|
g_free (contents);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fwrite ((const void *) contents, 1, length, backup_fd) != length)
|
|
|
|
ret1 = FALSE;
|
|
|
|
{
|
|
|
|
int ret2;
|
|
|
|
ret2 = fflush (backup_fd);
|
|
|
|
ret2 = fclose (backup_fd);
|
|
|
|
}
|
|
|
|
g_free (contents);
|
|
|
|
return ret1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/*** public functions ****************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2002-09-22 11:40:56 +04:00
|
|
|
int
|
|
|
|
is_printable (int c)
|
|
|
|
{
|
1998-02-27 07:54:42 +03:00
|
|
|
c &= 0xff;
|
2002-09-22 11:40:56 +04:00
|
|
|
|
2001-06-06 02:49:15 +04:00
|
|
|
#ifdef HAVE_CHARSET
|
2002-09-22 11:40:56 +04:00
|
|
|
/* "Display bits" is ignored, since the user controls the output
|
|
|
|
by setting the output codepage */
|
|
|
|
return is_8bit_printable (c);
|
2001-06-06 02:49:15 +04:00
|
|
|
#else
|
2011-02-10 18:02:54 +03:00
|
|
|
if (!mc_global.eight_bit_clean)
|
2010-02-26 12:25:53 +03:00
|
|
|
return is_7bit_printable (c);
|
2002-09-22 11:40:56 +04:00
|
|
|
|
2011-02-10 18:02:54 +03:00
|
|
|
if (mc_global.full_eight_bits)
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
|
|
|
return is_8bit_printable (c);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return is_iso_printable (c);
|
|
|
|
#endif /* !HAVE_CHARSET */
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
2003-01-29 01:52:04 +03:00
|
|
|
* Quote the filename for the purpose of inserting it into the command
|
|
|
|
* line. If quote_percent is 1, replace "%" with "%%" - the percent is
|
|
|
|
* processed by the mc command line.
|
|
|
|
*/
|
1998-02-27 07:54:42 +03:00
|
|
|
char *
|
|
|
|
name_quote (const char *s, int quote_percent)
|
|
|
|
{
|
|
|
|
char *ret, *d;
|
2003-01-29 01:52:04 +03:00
|
|
|
|
|
|
|
d = ret = g_malloc (strlen (s) * 2 + 2 + 1);
|
2010-02-26 12:25:53 +03:00
|
|
|
if (*s == '-')
|
|
|
|
{
|
|
|
|
*d++ = '.';
|
|
|
|
*d++ = '/';
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
for (; *s; s++, d++)
|
|
|
|
{
|
|
|
|
switch (*s)
|
|
|
|
{
|
|
|
|
case '%':
|
|
|
|
if (quote_percent)
|
|
|
|
*d++ = '%';
|
|
|
|
break;
|
|
|
|
case '\'':
|
|
|
|
case '\\':
|
|
|
|
case '\r':
|
|
|
|
case '\n':
|
|
|
|
case '\t':
|
|
|
|
case '"':
|
|
|
|
case ';':
|
|
|
|
case ' ':
|
|
|
|
case '?':
|
|
|
|
case '|':
|
|
|
|
case '[':
|
|
|
|
case ']':
|
|
|
|
case '{':
|
|
|
|
case '}':
|
|
|
|
case '<':
|
|
|
|
case '>':
|
|
|
|
case '`':
|
|
|
|
case '!':
|
|
|
|
case '$':
|
|
|
|
case '&':
|
|
|
|
case '*':
|
|
|
|
case '(':
|
|
|
|
case ')':
|
|
|
|
*d++ = '\\';
|
|
|
|
break;
|
|
|
|
case '~':
|
|
|
|
case '#':
|
|
|
|
if (d == ret)
|
|
|
|
*d++ = '\\';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*d = *s;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
*d = '\0';
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
char *
|
|
|
|
fake_name_quote (const char *s, int quote_percent)
|
|
|
|
{
|
2005-02-09 01:33:52 +03:00
|
|
|
(void) quote_percent;
|
2009-02-06 01:40:32 +03:00
|
|
|
return g_strdup (s);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
2010-11-09 21:53:22 +03:00
|
|
|
* path_trunc() is the same as str_trunc() but
|
2004-11-03 22:43:17 +03:00
|
|
|
* it deletes possible password from path for security
|
|
|
|
* reasons.
|
|
|
|
*/
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2004-11-03 22:43:17 +03:00
|
|
|
const char *
|
2010-02-26 12:25:53 +03:00
|
|
|
path_trunc (const char *path, size_t trunc_len)
|
|
|
|
{
|
2009-02-06 01:40:32 +03:00
|
|
|
char *secure_path = strip_password (g_strdup (path), 1);
|
2009-04-04 23:50:46 +04:00
|
|
|
|
patches by Rostislav Beneš: mc-28-fix
rest of fixes in files cmc.c, main.c (xterm title), panelize.c, subshell.c,
tree.c, tty.c, user.c, util.c, win.c
now, basic mc's function should work well, editor and view are still broken.
2008-12-29 02:53:08 +03:00
|
|
|
const char *ret = str_trunc (secure_path, trunc_len);
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (secure_path);
|
2009-04-04 23:50:46 +04:00
|
|
|
|
2004-11-03 22:43:17 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
const char *
|
2010-11-27 16:35:59 +03:00
|
|
|
size_trunc (uintmax_t size, gboolean use_si)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
static char x[BUF_TINY];
|
2010-11-27 16:35:59 +03:00
|
|
|
uintmax_t divisor = 1;
|
2004-08-29 20:42:40 +04:00
|
|
|
const char *xtra = "";
|
2010-02-26 12:25:53 +03:00
|
|
|
|
2010-11-27 16:35:59 +03:00
|
|
|
if (size > 999999999UL)
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
2010-03-09 22:03:51 +03:00
|
|
|
divisor = use_si ? 1000 : 1024;
|
|
|
|
xtra = use_si ? "k" : "K";
|
2011-08-10 10:23:46 +04:00
|
|
|
|
2010-11-27 16:35:59 +03:00
|
|
|
if (size / divisor > 999999999UL)
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
2010-03-09 22:03:51 +03:00
|
|
|
divisor = use_si ? (1000 * 1000) : (1024 * 1024);
|
|
|
|
xtra = use_si ? "m" : "M";
|
2011-08-10 10:23:46 +04:00
|
|
|
|
|
|
|
if (size / divisor > 999999999UL)
|
|
|
|
{
|
|
|
|
divisor = use_si ? (1000 * 1000 * 1000) : (1024 * 1024 * 1024);
|
|
|
|
xtra = use_si ? "g" : "G";
|
|
|
|
}
|
2010-02-26 12:25:53 +03:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2010-11-27 16:35:59 +03:00
|
|
|
g_snprintf (x, sizeof (x), "%.0f%s", 1.0 * size / divisor, xtra);
|
1998-02-27 07:54:42 +03:00
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
const char *
|
2010-11-27 16:35:59 +03:00
|
|
|
size_trunc_sep (uintmax_t size, gboolean use_si)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
static char x[60];
|
|
|
|
int count;
|
2004-08-30 03:20:01 +04:00
|
|
|
const char *p, *y;
|
|
|
|
char *d;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-03-09 22:03:51 +03:00
|
|
|
p = y = size_trunc (size, use_si);
|
1998-02-27 07:54:42 +03:00
|
|
|
p += strlen (p) - 1;
|
|
|
|
d = x + sizeof (x) - 1;
|
2010-11-27 16:35:59 +03:00
|
|
|
*d-- = '\0';
|
2002-07-03 23:47:40 +04:00
|
|
|
while (p >= y && isalpha ((unsigned char) *p))
|
2010-02-26 12:25:53 +03:00
|
|
|
*d-- = *p--;
|
|
|
|
for (count = 0; p >= y; count++)
|
|
|
|
{
|
|
|
|
if (count == 3)
|
|
|
|
{
|
|
|
|
*d-- = ',';
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
*d-- = *p--;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
d++;
|
|
|
|
if (*d == ',')
|
2010-02-26 12:25:53 +03:00
|
|
|
d++;
|
1998-02-27 07:54:42 +03:00
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
2001-06-28 08:17:28 +04:00
|
|
|
* Print file SIZE to BUFFER, but don't exceed LEN characters,
|
|
|
|
* not including trailing 0. BUFFER should be at least LEN+1 long.
|
|
|
|
* This function is called for every file on panels, so avoid
|
|
|
|
* floating point by any means.
|
2001-08-30 20:41:08 +04:00
|
|
|
*
|
|
|
|
* Units: size units (filesystem sizes are 1K blocks)
|
|
|
|
* 0=bytes, 1=Kbytes, 2=Mbytes, etc.
|
2001-06-28 08:17:28 +04:00
|
|
|
*/
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2001-06-28 08:17:28 +04:00
|
|
|
void
|
2010-11-27 16:35:59 +03:00
|
|
|
size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gboolean use_si)
|
2001-06-28 08:17:28 +04:00
|
|
|
{
|
|
|
|
/* Avoid taking power for every file. */
|
2011-09-06 14:35:42 +04:00
|
|
|
/* *INDENT-OFF* */
|
2010-12-29 18:12:59 +03:00
|
|
|
static const uintmax_t power10[] = {
|
2011-08-09 14:53:54 +04:00
|
|
|
/* we hope that size of uintmax_t is 4 bytes at least */
|
|
|
|
1ULL,
|
|
|
|
10ULL,
|
|
|
|
100ULL,
|
|
|
|
1000ULL,
|
|
|
|
10000ULL,
|
|
|
|
100000ULL,
|
|
|
|
1000000ULL,
|
|
|
|
10000000ULL,
|
|
|
|
100000000ULL,
|
|
|
|
1000000000ULL
|
|
|
|
/* maximmum value of uintmax_t (in case of 4 bytes) is
|
|
|
|
4294967295
|
|
|
|
*/
|
|
|
|
#if SIZEOF_UINTMAX_T == 8
|
|
|
|
,
|
|
|
|
10000000000ULL,
|
|
|
|
100000000000ULL,
|
|
|
|
1000000000000ULL,
|
|
|
|
10000000000000ULL,
|
|
|
|
100000000000000ULL,
|
|
|
|
1000000000000000ULL,
|
|
|
|
10000000000000000ULL,
|
|
|
|
100000000000000000ULL,
|
|
|
|
1000000000000000000ULL,
|
|
|
|
10000000000000000000ULL
|
|
|
|
/* maximmum value of uintmax_t (in case of 8 bytes) is
|
|
|
|
18447644073710439615
|
|
|
|
*/
|
|
|
|
#endif
|
2010-02-26 12:25:53 +03:00
|
|
|
};
|
2011-09-06 14:35:42 +04:00
|
|
|
/* *INDENT-ON* */
|
2010-02-26 12:25:53 +03:00
|
|
|
static const char *const suffix[] = { "", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL };
|
|
|
|
static const char *const suffix_lc[] = { "", "k", "m", "g", "t", "p", "e", "z", "y", NULL };
|
2001-06-28 08:17:28 +04:00
|
|
|
int j = 0;
|
|
|
|
|
2009-08-29 12:32:24 +04:00
|
|
|
if (len == 0)
|
2010-02-26 12:25:53 +03:00
|
|
|
len = 9;
|
2011-08-09 14:53:54 +04:00
|
|
|
#if SIZEOF_UINTMAX_T == 8
|
|
|
|
/* 20 decimal digits are required to represent 8 bytes */
|
|
|
|
else if (len > 19)
|
|
|
|
len = 19;
|
|
|
|
#else
|
|
|
|
/* 10 decimal digits are required to represent 4 bytes */
|
|
|
|
else if (len > 9)
|
|
|
|
len = 9;
|
|
|
|
#endif
|
2001-06-28 08:17:28 +04:00
|
|
|
|
2009-08-15 22:03:24 +04:00
|
|
|
/*
|
|
|
|
* recalculate from 1024 base to 1000 base if units>0
|
|
|
|
* We can't just multiply by 1024 - that might cause overflow
|
|
|
|
* if off_t type is too small
|
|
|
|
*/
|
2010-11-27 16:35:59 +03:00
|
|
|
if (use_si)
|
2010-02-26 12:25:53 +03:00
|
|
|
for (j = 0; j < units; j++)
|
|
|
|
{
|
2011-09-23 11:20:36 +04:00
|
|
|
uintmax_t size_remain;
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
size_remain = ((size % 125) * 1024) / 1000; /* size mod 125, recalculated */
|
|
|
|
size = size / 125; /* 128/125 = 1024/1000 */
|
|
|
|
size = size * 128; /* This will convert size from multiple of 1024 to multiple of 1000 */
|
|
|
|
size += size_remain; /* Re-add remainder lost by division/multiplication */
|
|
|
|
}
|
2009-08-15 22:03:24 +04:00
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
for (j = units; suffix[j] != NULL; j++)
|
|
|
|
{
|
|
|
|
if (size == 0)
|
|
|
|
{
|
|
|
|
if (j == units)
|
|
|
|
{
|
|
|
|
/* Empty files will print "0" even with minimal width. */
|
|
|
|
g_snprintf (buffer, len + 1, "0");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use "~K" or just "K" if len is 1. Use "B" for bytes. */
|
|
|
|
g_snprintf (buffer, len + 1, (len > 1) ? "~%s" : "%s",
|
2010-03-09 22:03:51 +03:00
|
|
|
(j > 1) ? (use_si ? suffix_lc[j - 1] : suffix[j - 1]) : "B");
|
2010-02-26 12:25:53 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-08-09 14:53:54 +04:00
|
|
|
if (size < power10[len - (j > 0 ? 1 : 0)])
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
2010-12-02 21:50:57 +03:00
|
|
|
g_snprintf (buffer, len + 1, "%" PRIuMAX "%s", size, use_si ? suffix_lc[j] : suffix[j]);
|
2010-02-26 12:25:53 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Powers of 1000 or 1024, with rounding. */
|
2010-03-09 22:03:51 +03:00
|
|
|
if (use_si)
|
2010-02-26 12:25:53 +03:00
|
|
|
size = (size + 500) / 1000;
|
|
|
|
else
|
|
|
|
size = (size + 512) >> 10;
|
2001-06-28 08:17:28 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2004-08-30 03:20:01 +04:00
|
|
|
const char *
|
2002-09-06 23:23:45 +04:00
|
|
|
string_perm (mode_t mode_bits)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2002-09-06 23:23:45 +04:00
|
|
|
static char mode[11];
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
strcpy (mode, "----------");
|
2002-09-06 23:23:45 +04:00
|
|
|
if (S_ISDIR (mode_bits))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[0] = 'd';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (S_ISCHR (mode_bits))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[0] = 'c';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (S_ISBLK (mode_bits))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[0] = 'b';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (S_ISLNK (mode_bits))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[0] = 'l';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (S_ISFIFO (mode_bits))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[0] = 'p';
|
2004-11-03 23:31:59 +03:00
|
|
|
if (S_ISNAM (mode_bits))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[0] = 'n';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (S_ISSOCK (mode_bits))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[0] = 's';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (S_ISDOOR (mode_bits))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[0] = 'D';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (ismode (mode_bits, S_IXOTH))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[9] = 'x';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (ismode (mode_bits, S_IWOTH))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[8] = 'w';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (ismode (mode_bits, S_IROTH))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[7] = 'r';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (ismode (mode_bits, S_IXGRP))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[6] = 'x';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (ismode (mode_bits, S_IWGRP))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[5] = 'w';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (ismode (mode_bits, S_IRGRP))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[4] = 'r';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (ismode (mode_bits, S_IXUSR))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[3] = 'x';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (ismode (mode_bits, S_IWUSR))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[2] = 'w';
|
2002-09-06 23:23:45 +04:00
|
|
|
if (ismode (mode_bits, S_IRUSR))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[1] = 'r';
|
2002-09-06 23:23:45 +04:00
|
|
|
#ifdef S_ISUID
|
|
|
|
if (ismode (mode_bits, S_ISUID))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[3] = (mode[3] == 'x') ? 's' : 'S';
|
|
|
|
#endif /* S_ISUID */
|
2002-09-06 23:23:45 +04:00
|
|
|
#ifdef S_ISGID
|
|
|
|
if (ismode (mode_bits, S_ISGID))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[6] = (mode[6] == 'x') ? 's' : 'S';
|
|
|
|
#endif /* S_ISGID */
|
2002-09-06 23:23:45 +04:00
|
|
|
#ifdef S_ISVTX
|
|
|
|
if (ismode (mode_bits, S_ISVTX))
|
2010-02-26 12:25:53 +03:00
|
|
|
mode[9] = (mode[9] == 'x') ? 't' : 'T';
|
|
|
|
#endif /* S_ISVTX */
|
1998-02-27 07:54:42 +03:00
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* p: string which might contain an url with a password (this parameter is
|
|
|
|
* modified in place).
|
|
|
|
* has_prefix = 0: The first parameter is an url without a prefix
|
|
|
|
* (user[:pass]@]machine[:port][remote-dir). Delete
|
|
|
|
* the password.
|
|
|
|
* has_prefix = 1: Search p for known url prefixes. If found delete
|
|
|
|
* the password from the url.
|
|
|
|
* Caveat: only the first url is found
|
2010-02-26 12:25:53 +03:00
|
|
|
*/
|
2010-11-08 13:21:45 +03:00
|
|
|
|
1999-02-04 02:19:40 +03:00
|
|
|
char *
|
|
|
|
strip_password (char *p, int has_prefix)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
static const struct
|
|
|
|
{
|
|
|
|
const char *name;
|
1999-02-04 02:19:40 +03:00
|
|
|
size_t len;
|
2010-02-26 12:25:53 +03:00
|
|
|
} prefixes[] =
|
|
|
|
{
|
2010-05-27 22:02:45 +04:00
|
|
|
/* *INDENT-OFF* */
|
|
|
|
{ "/#ftp:", 6 },
|
|
|
|
{ "ftp://", 6 },
|
|
|
|
{ "/#smb:", 6 },
|
|
|
|
{ "smb://", 6 },
|
|
|
|
{ "/#sh:", 5 },
|
|
|
|
{ "sh://", 5 },
|
|
|
|
{ "ssh://", 6 }
|
|
|
|
/* *INDENT-ON* */
|
1999-02-04 02:19:40 +03:00
|
|
|
};
|
2010-05-27 22:02:45 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
char *at, *inner_colon, *dir;
|
2004-08-16 07:12:05 +04:00
|
|
|
size_t i;
|
1999-02-04 02:19:40 +03:00
|
|
|
char *result = p;
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
for (i = 0; i < sizeof (prefixes) / sizeof (prefixes[0]); i++)
|
|
|
|
{
|
|
|
|
char *q;
|
|
|
|
|
|
|
|
if (has_prefix)
|
|
|
|
{
|
2010-03-30 22:59:41 +04:00
|
|
|
q = strstr (p, prefixes[i].name);
|
|
|
|
if (q == NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
continue;
|
1999-02-04 02:19:40 +03:00
|
|
|
else
|
2010-02-26 12:25:53 +03:00
|
|
|
p = q + prefixes[i].len;
|
|
|
|
}
|
1999-02-04 02:19:40 +03:00
|
|
|
|
2010-03-30 22:59:41 +04:00
|
|
|
dir = strchr (p, PATH_SEP);
|
|
|
|
if (dir != NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
*dir = '\0';
|
2004-11-09 15:30:29 +03:00
|
|
|
|
1999-02-04 02:19:40 +03:00
|
|
|
/* search for any possible user */
|
2004-10-05 18:25:28 +04:00
|
|
|
at = strrchr (p, '@');
|
1999-02-04 02:19:40 +03:00
|
|
|
|
2004-11-09 15:30:29 +03:00
|
|
|
if (dir)
|
2010-02-26 12:25:53 +03:00
|
|
|
*dir = PATH_SEP;
|
2004-11-09 15:30:29 +03:00
|
|
|
|
1999-02-04 02:19:40 +03:00
|
|
|
/* We have a username */
|
2010-02-26 12:25:53 +03:00
|
|
|
if (at)
|
|
|
|
{
|
|
|
|
inner_colon = memchr (p, ':', at - p);
|
1999-02-04 02:19:40 +03:00
|
|
|
if (inner_colon)
|
2010-02-26 12:25:53 +03:00
|
|
|
memmove (inner_colon, at, strlen (at) + 1);
|
1999-02-04 02:19:40 +03:00
|
|
|
}
|
2010-02-26 12:25:53 +03:00
|
|
|
break;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
1999-02-04 02:19:40 +03:00
|
|
|
return (result);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
const char *
|
2010-02-26 12:25:53 +03:00
|
|
|
strip_home_and_password (const char *dir)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
1999-04-28 08:03:30 +04:00
|
|
|
size_t len;
|
2010-02-26 12:25:53 +03:00
|
|
|
static char newdir[MC_MAXPATHLEN];
|
|
|
|
|
2010-12-29 18:12:59 +03:00
|
|
|
len = strlen (mc_config_get_home_dir ());
|
|
|
|
if (mc_config_get_home_dir () != NULL && strncmp (dir, mc_config_get_home_dir (), len) == 0 &&
|
2010-02-26 12:25:53 +03:00
|
|
|
(dir[len] == PATH_SEP || dir[len] == '\0'))
|
|
|
|
{
|
|
|
|
newdir[0] = '~';
|
|
|
|
g_strlcpy (&newdir[1], &dir[len], sizeof (newdir) - 1);
|
|
|
|
return newdir;
|
|
|
|
}
|
1998-05-26 04:53:24 +04:00
|
|
|
|
1999-02-04 02:19:40 +03:00
|
|
|
/* We do not strip homes in /#ftp tree, I do not like ~'s there
|
|
|
|
(see ftpfs.c why) */
|
2010-02-26 12:25:53 +03:00
|
|
|
g_strlcpy (newdir, dir, sizeof (newdir));
|
1999-02-04 02:19:40 +03:00
|
|
|
strip_password (newdir, 1);
|
|
|
|
return newdir;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
const char *
|
|
|
|
extension (const char *filename)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-12-02 22:39:21 +03:00
|
|
|
const char *d = strrchr (filename, '.');
|
|
|
|
return (d != NULL) ? d + 1 : "";
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2009-05-21 09:13:12 +04:00
|
|
|
|
2003-11-20 21:38:29 +03:00
|
|
|
char *
|
2010-09-16 14:11:48 +04:00
|
|
|
load_mc_home_file (const char *from, const char *filename, char **allocated_filename)
|
2001-06-09 11:13:46 +04:00
|
|
|
{
|
|
|
|
char *hintfile_base, *hintfile;
|
|
|
|
char *lang;
|
|
|
|
char *data;
|
|
|
|
|
2010-09-16 14:11:48 +04:00
|
|
|
hintfile_base = g_build_filename (from, filename, (char *) NULL);
|
2001-09-16 04:18:39 +04:00
|
|
|
lang = guess_message_value ();
|
2001-06-09 11:13:46 +04:00
|
|
|
|
2004-09-24 19:05:28 +04:00
|
|
|
hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
|
2010-11-11 10:38:41 +03:00
|
|
|
if (!g_file_get_contents (hintfile, &data, NULL, NULL))
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
2010-09-16 14:11:48 +04:00
|
|
|
/* Fall back to the two-letter language code */
|
|
|
|
if (lang[0] != '\0' && lang[1] != '\0')
|
|
|
|
lang[2] = '\0';
|
2010-02-26 12:25:53 +03:00
|
|
|
g_free (hintfile);
|
|
|
|
hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
|
2010-11-11 10:38:41 +03:00
|
|
|
if (!g_file_get_contents (hintfile, &data, NULL, NULL))
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
2010-03-11 15:38:11 +03:00
|
|
|
g_free (hintfile);
|
2010-09-16 14:11:48 +04:00
|
|
|
hintfile = hintfile_base;
|
2010-11-11 10:38:41 +03:00
|
|
|
g_file_get_contents (hintfile_base, &data, NULL, NULL);
|
2010-02-26 12:25:53 +03:00
|
|
|
}
|
2001-06-09 11:13:46 +04:00
|
|
|
}
|
|
|
|
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (lang);
|
2001-06-09 11:13:46 +04:00
|
|
|
|
|
|
|
if (hintfile != hintfile_base)
|
2010-02-26 12:25:53 +03:00
|
|
|
g_free (hintfile_base);
|
2001-06-09 11:13:46 +04:00
|
|
|
|
2010-09-16 14:11:48 +04:00
|
|
|
if (allocated_filename != NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
*allocated_filename = hintfile;
|
2001-06-09 11:13:46 +04:00
|
|
|
else
|
2010-02-26 12:25:53 +03:00
|
|
|
g_free (hintfile);
|
2001-06-09 11:13:46 +04:00
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
const char *
|
|
|
|
extract_line (const char *s, const char *top)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
static char tmp_line[BUF_MEDIUM];
|
1998-02-27 07:54:42 +03:00
|
|
|
char *t = tmp_line;
|
2010-02-26 12:25:53 +03:00
|
|
|
|
|
|
|
while (*s && *s != '\n' && (size_t) (t - tmp_line) < sizeof (tmp_line) - 1 && s < top)
|
|
|
|
*t++ = *s++;
|
1998-02-27 07:54:42 +03:00
|
|
|
*t = 0;
|
|
|
|
return tmp_line;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* The basename routine
|
|
|
|
*/
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
const char *
|
|
|
|
x_basename (const char *s)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2011-06-17 19:32:51 +04:00
|
|
|
const char *url_delim, *path_sep;
|
2011-06-14 16:09:59 +04:00
|
|
|
|
2011-06-17 19:32:51 +04:00
|
|
|
url_delim = g_strrstr (s, VFS_PATH_URL_DELIMITER);
|
|
|
|
path_sep = strrchr (s, PATH_SEP);
|
2011-06-14 16:09:59 +04:00
|
|
|
|
2011-06-17 19:32:51 +04:00
|
|
|
if (url_delim == NULL
|
|
|
|
|| url_delim < path_sep - strlen (VFS_PATH_URL_DELIMITER)
|
|
|
|
|| url_delim - s + strlen (VFS_PATH_URL_DELIMITER) < strlen (s))
|
|
|
|
{
|
|
|
|
/* avoid trailing PATH_SEP, if present */
|
|
|
|
if (s[strlen (s) - 1] == PATH_SEP)
|
|
|
|
{
|
|
|
|
while (--path_sep > s && *path_sep != PATH_SEP);
|
|
|
|
return (path_sep != s) ? path_sep + 1 : s;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return (path_sep != NULL) ? path_sep + 1 : s;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (--url_delim > s && *url_delim != PATH_SEP);
|
|
|
|
while (--url_delim > s && *url_delim != PATH_SEP);
|
2011-06-14 16:09:59 +04:00
|
|
|
|
2011-06-17 19:32:51 +04:00
|
|
|
return (url_delim == s) ? s : url_delim + 1;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
const char *
|
|
|
|
unix_error_string (int error_num)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
static char buffer[BUF_LARGE];
|
2003-05-29 08:33:38 +04:00
|
|
|
gchar *strerror_currentlocale;
|
2009-11-02 15:12:56 +03:00
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
strerror_currentlocale = g_locale_from_utf8 (g_strerror (error_num), -1, NULL, NULL, NULL);
|
|
|
|
g_snprintf (buffer, sizeof (buffer), "%s (%d)", strerror_currentlocale, error_num);
|
|
|
|
g_free (strerror_currentlocale);
|
2009-11-02 15:12:56 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
const char *
|
|
|
|
skip_separators (const char *s)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
patches by Rostislav Beneš: mc-28-fix
rest of fixes in files cmc.c, main.c (xterm title), panelize.c, subshell.c,
tree.c, tty.c, user.c, util.c, win.c
now, basic mc's function should work well, editor and view are still broken.
2008-12-29 02:53:08 +03:00
|
|
|
const char *su = s;
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
for (; *su; str_cnext_char (&su))
|
|
|
|
if (*su != ' ' && *su != '\t' && *su != ',')
|
|
|
|
break;
|
patches by Rostislav Beneš: mc-28-fix
rest of fixes in files cmc.c, main.c (xterm title), panelize.c, subshell.c,
tree.c, tty.c, user.c, util.c, win.c
now, basic mc's function should work well, editor and view are still broken.
2008-12-29 02:53:08 +03:00
|
|
|
|
|
|
|
return su;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
const char *
|
|
|
|
skip_numbers (const char *s)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
patches by Rostislav Beneš: mc-28-fix
rest of fixes in files cmc.c, main.c (xterm title), panelize.c, subshell.c,
tree.c, tty.c, user.c, util.c, win.c
now, basic mc's function should work well, editor and view are still broken.
2008-12-29 02:53:08 +03:00
|
|
|
const char *su = s;
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
for (; *su; str_cnext_char (&su))
|
|
|
|
if (!str_isdigit (su))
|
|
|
|
break;
|
patches by Rostislav Beneš: mc-28-fix
rest of fixes in files cmc.c, main.c (xterm title), panelize.c, subshell.c,
tree.c, tty.c, user.c, util.c, win.c
now, basic mc's function should work well, editor and view are still broken.
2008-12-29 02:53:08 +03:00
|
|
|
|
|
|
|
return su;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* Remove all control sequences from the argument string. We define
|
1998-02-27 07:54:42 +03:00
|
|
|
* "control sequence", in a sort of pidgin BNF, as follows:
|
|
|
|
*
|
|
|
|
* control-seq = Esc non-'['
|
2010-02-26 12:25:53 +03:00
|
|
|
* | Esc '[' (0 or more digits or ';' or '?') (any other char)
|
1998-02-27 07:54:42 +03:00
|
|
|
*
|
|
|
|
* This scheme works for all the terminals described in my termcap /
|
|
|
|
* terminfo databases, except the Hewlett-Packard 70092 and some Wyse
|
|
|
|
* terminals. If I hear from a single person who uses such a terminal
|
|
|
|
* with MC, I'll be glad to add support for it. (Dugan)
|
2001-08-16 07:52:51 +04:00
|
|
|
* Non-printable characters are also removed.
|
1998-02-27 07:54:42 +03:00
|
|
|
*/
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
char *
|
|
|
|
strip_ctrl_codes (char *s)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
char *w; /* Current position where the stripped data is written */
|
|
|
|
char *r; /* Current position where the original data is read */
|
patches by Rostislav Beneš: mc-28-fix
rest of fixes in files cmc.c, main.c (xterm title), panelize.c, subshell.c,
tree.c, tty.c, user.c, util.c, win.c
now, basic mc's function should work well, editor and view are still broken.
2008-12-29 02:53:08 +03:00
|
|
|
char *n;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
if (!s)
|
2010-02-26 12:25:53 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (w = s, r = s; *r;)
|
|
|
|
{
|
|
|
|
if (*r == ESC_CHAR)
|
|
|
|
{
|
|
|
|
/* Skip the control sequence's arguments */ ;
|
|
|
|
/* '(' need to avoid strange 'B' letter in *Suse (if mc runs under root user) */
|
|
|
|
if (*(++r) == '[' || *r == '(')
|
|
|
|
{
|
|
|
|
/* strchr() matches trailing binary 0 */
|
|
|
|
while (*(++r) && strchr ("0123456789;?", *r));
|
|
|
|
}
|
|
|
|
else if (*r == ']')
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Skip xterm's OSC (Operating System Command)
|
|
|
|
* http://www.xfree86.org/current/ctlseqs.html
|
|
|
|
* OSC P s ; P t ST
|
|
|
|
* OSC P s ; P t BEL
|
|
|
|
*/
|
|
|
|
char *new_r = r;
|
|
|
|
|
|
|
|
for (; *new_r; ++new_r)
|
|
|
|
{
|
|
|
|
switch (*new_r)
|
|
|
|
{
|
|
|
|
/* BEL */
|
|
|
|
case '\a':
|
|
|
|
r = new_r;
|
|
|
|
goto osc_out;
|
|
|
|
case ESC_CHAR:
|
|
|
|
/* ST */
|
|
|
|
if (*(new_r + 1) == '\\')
|
|
|
|
{
|
|
|
|
r = new_r + 1;
|
|
|
|
goto osc_out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
osc_out:;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we are at the last character of the sequence.
|
|
|
|
* Skip it unless it's binary 0.
|
|
|
|
*/
|
|
|
|
if (*r)
|
|
|
|
r++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = str_get_next_char (r);
|
|
|
|
if (str_isprint (r))
|
|
|
|
{
|
|
|
|
memmove (w, r, n - r);
|
|
|
|
w += n - r;
|
|
|
|
}
|
|
|
|
r = n;
|
2002-08-15 10:53:44 +04:00
|
|
|
}
|
2001-08-16 07:52:51 +04:00
|
|
|
*w = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-07-14 10:31:29 +04:00
|
|
|
enum compression_type
|
2010-02-26 12:25:53 +03:00
|
|
|
get_compression_type (int fd, const char *name)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2009-01-24 08:11:35 +03:00
|
|
|
unsigned char magic[16];
|
2009-10-28 01:51:39 +03:00
|
|
|
size_t str_len;
|
2002-07-03 01:25:49 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Read the magic signature */
|
2003-01-27 21:19:34 +03:00
|
|
|
if (mc_read (fd, (char *) magic, 4) != 4)
|
2010-02-26 12:25:53 +03:00
|
|
|
return COMPRESSION_NONE;
|
2002-07-03 01:25:49 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* GZIP_MAGIC and OLD_GZIP_MAGIC */
|
2010-02-26 12:25:53 +03:00
|
|
|
if (magic[0] == 037 && (magic[1] == 0213 || magic[1] == 0236))
|
|
|
|
{
|
|
|
|
return COMPRESSION_GZIP;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* PKZIP_MAGIC */
|
2010-02-26 12:25:53 +03:00
|
|
|
if (magic[0] == 0120 && magic[1] == 0113 && magic[2] == 003 && magic[3] == 004)
|
|
|
|
{
|
|
|
|
/* Read compression type */
|
|
|
|
mc_lseek (fd, 8, SEEK_SET);
|
|
|
|
if (mc_read (fd, (char *) magic, 2) != 2)
|
|
|
|
return COMPRESSION_NONE;
|
|
|
|
|
|
|
|
/* Gzip can handle only deflated (8) or stored (0) files */
|
|
|
|
if ((magic[0] != 8 && magic[0] != 0) || magic[1] != 0)
|
|
|
|
return COMPRESSION_NONE;
|
|
|
|
|
|
|
|
/* Compatible with gzip */
|
|
|
|
return COMPRESSION_GZIP;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* PACK_MAGIC and LZH_MAGIC and compress magic */
|
2010-02-26 12:25:53 +03:00
|
|
|
if (magic[0] == 037 && (magic[1] == 036 || magic[1] == 0240 || magic[1] == 0235))
|
|
|
|
{
|
|
|
|
/* Compatible with gzip */
|
|
|
|
return COMPRESSION_GZIP;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* BZIP and BZIP2 files */
|
2010-02-26 12:25:53 +03:00
|
|
|
if ((magic[0] == 'B') && (magic[1] == 'Z') && (magic[3] >= '1') && (magic[3] <= '9'))
|
|
|
|
{
|
|
|
|
switch (magic[2])
|
|
|
|
{
|
|
|
|
case '0':
|
|
|
|
return COMPRESSION_BZIP;
|
|
|
|
case 'h':
|
|
|
|
return COMPRESSION_BZIP2;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2009-01-24 08:11:35 +03:00
|
|
|
|
2009-07-15 21:31:56 +04:00
|
|
|
/* Support for LZMA (only utils format with magic in header).
|
|
|
|
* This is the default format of LZMA utils 4.32.1 and later. */
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
if (mc_read (fd, (char *) magic + 4, 2) != 2)
|
|
|
|
return COMPRESSION_NONE;
|
2009-11-09 14:42:27 +03:00
|
|
|
|
|
|
|
/* LZMA utils format */
|
2010-02-26 12:25:53 +03:00
|
|
|
if (magic[0] == 0xFF
|
|
|
|
&& magic[1] == 'L'
|
|
|
|
&& magic[2] == 'Z' && magic[3] == 'M' && magic[4] == 'A' && magic[5] == 0x00)
|
|
|
|
return COMPRESSION_LZMA;
|
2009-01-24 08:11:35 +03:00
|
|
|
|
2009-05-12 06:00:51 +04:00
|
|
|
/* XZ compression magic */
|
2010-02-26 12:25:53 +03:00
|
|
|
if (magic[0] == 0xFD
|
|
|
|
&& magic[1] == 0x37
|
|
|
|
&& magic[2] == 0x7A && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00)
|
|
|
|
return COMPRESSION_XZ;
|
|
|
|
|
|
|
|
str_len = strlen (name);
|
|
|
|
/* HACK: we must belive to extention of LZMA file :) ... */
|
|
|
|
if ((str_len > 5 && strcmp (&name[str_len - 5], ".lzma") == 0) ||
|
|
|
|
(str_len > 4 && strcmp (&name[str_len - 4], ".tlz") == 0))
|
|
|
|
return COMPRESSION_LZMA;
|
2009-05-12 06:00:51 +04:00
|
|
|
|
2009-07-15 21:31:56 +04:00
|
|
|
return COMPRESSION_NONE;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2002-11-12 14:20:08 +03:00
|
|
|
const char *
|
1998-09-22 15:20:32 +04:00
|
|
|
decompress_extension (int type)
|
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case COMPRESSION_GZIP:
|
2011-06-14 16:09:59 +04:00
|
|
|
return "/ugz" VFS_PATH_URL_DELIMITER;
|
2010-02-26 12:25:53 +03:00
|
|
|
case COMPRESSION_BZIP:
|
2011-06-14 16:09:59 +04:00
|
|
|
return "/ubz" VFS_PATH_URL_DELIMITER;
|
2010-02-26 12:25:53 +03:00
|
|
|
case COMPRESSION_BZIP2:
|
2011-06-14 16:09:59 +04:00
|
|
|
return "/ubz2" VFS_PATH_URL_DELIMITER;
|
2010-02-26 12:25:53 +03:00
|
|
|
case COMPRESSION_LZMA:
|
2011-06-14 16:09:59 +04:00
|
|
|
return "/ulzma" VFS_PATH_URL_DELIMITER;
|
2010-02-26 12:25:53 +03:00
|
|
|
case COMPRESSION_XZ:
|
2011-06-14 16:09:59 +04:00
|
|
|
return "/uxz" VFS_PATH_URL_DELIMITER;
|
2010-02-26 12:25:53 +03:00
|
|
|
}
|
|
|
|
/* Should never reach this place */
|
|
|
|
fprintf (stderr, "Fatal: decompress_extension called with an unknown argument\n");
|
|
|
|
return 0;
|
1998-09-22 15:20:32 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
void
|
|
|
|
wipe_password (char *passwd)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
char *p = passwd;
|
2010-02-26 12:25:53 +03:00
|
|
|
|
1999-09-14 22:20:02 +04:00
|
|
|
if (!p)
|
2010-02-26 12:25:53 +03:00
|
|
|
return;
|
|
|
|
for (; *p; p++)
|
1998-02-27 07:54:42 +03:00
|
|
|
*p = 0;
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (passwd);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* Convert "\E" -> esc character and ^x to control-x key and ^^ to ^ key
|
|
|
|
* @returns a newly allocated string
|
|
|
|
*/
|
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
char *
|
|
|
|
convert_controls (const char *p)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2009-02-06 01:40:32 +03:00
|
|
|
char *valcopy = g_strdup (p);
|
2004-09-27 15:26:53 +04:00
|
|
|
char *q;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* Parse the escape special character */
|
2010-02-26 12:25:53 +03:00
|
|
|
for (q = valcopy; *p;)
|
|
|
|
{
|
|
|
|
if (*p == '\\')
|
|
|
|
{
|
|
|
|
p++;
|
|
|
|
if ((*p == 'e') || (*p == 'E'))
|
|
|
|
{
|
|
|
|
p++;
|
|
|
|
*q++ = ESC_CHAR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (*p == '^')
|
|
|
|
{
|
|
|
|
p++;
|
|
|
|
if (*p == '^')
|
|
|
|
*q++ = *p++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char c = (*p | 0x20);
|
|
|
|
if (c >= 'a' && c <= 'z')
|
|
|
|
{
|
|
|
|
*q++ = c - 'a' + 1;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
else if (*p)
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*q++ = *p++;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2002-08-14 20:33:50 +04:00
|
|
|
*q = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
return valcopy;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* Finds out a relative path from first to second, i.e. goes as many ..
|
|
|
|
* as needed up in first and then goes down using second
|
|
|
|
*/
|
2009-10-05 18:32:46 +04:00
|
|
|
|
2005-09-17 16:01:04 +04:00
|
|
|
char *
|
2010-02-26 12:25:53 +03:00
|
|
|
diff_two_paths (const char *first, const char *second)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2005-09-17 15:40:31 +04:00
|
|
|
char *p, *q, *r, *s, *buf = NULL;
|
1998-02-27 07:54:42 +03:00
|
|
|
int i, j, prevlen = -1, currlen;
|
2004-08-30 03:20:01 +04:00
|
|
|
char *my_first = NULL, *my_second = NULL;
|
2010-02-26 12:25:53 +03:00
|
|
|
|
2004-08-30 03:20:01 +04:00
|
|
|
my_first = resolve_symlinks (first);
|
|
|
|
if (my_first == NULL)
|
1998-02-27 07:54:42 +03:00
|
|
|
return NULL;
|
2005-09-17 15:40:31 +04:00
|
|
|
my_second = resolve_symlinks (second);
|
2010-02-26 12:25:53 +03:00
|
|
|
if (my_second == NULL)
|
|
|
|
{
|
|
|
|
g_free (my_first);
|
|
|
|
return NULL;
|
2005-09-17 15:40:31 +04:00
|
|
|
}
|
2010-02-26 12:25:53 +03:00
|
|
|
for (j = 0; j < 2; j++)
|
|
|
|
{
|
|
|
|
p = my_first;
|
|
|
|
q = my_second;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
r = strchr (p, PATH_SEP);
|
|
|
|
s = strchr (q, PATH_SEP);
|
|
|
|
if (!r || !s)
|
|
|
|
break;
|
|
|
|
*r = 0;
|
|
|
|
*s = 0;
|
|
|
|
if (strcmp (p, q))
|
|
|
|
{
|
|
|
|
*r = PATH_SEP;
|
|
|
|
*s = PATH_SEP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*r = PATH_SEP;
|
|
|
|
*s = PATH_SEP;
|
|
|
|
}
|
|
|
|
p = r + 1;
|
|
|
|
q = s + 1;
|
|
|
|
}
|
|
|
|
p--;
|
|
|
|
for (i = 0; (p = strchr (p + 1, PATH_SEP)) != NULL; i++);
|
|
|
|
currlen = (i + 1) * 3 + strlen (q) + 1;
|
|
|
|
if (j)
|
|
|
|
{
|
|
|
|
if (currlen < prevlen)
|
|
|
|
g_free (buf);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_free (my_first);
|
|
|
|
g_free (my_second);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p = buf = g_malloc (currlen);
|
|
|
|
prevlen = currlen;
|
|
|
|
for (; i >= 0; i--, p += 3)
|
|
|
|
strcpy (p, "../");
|
|
|
|
strcpy (p, q);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (my_first);
|
|
|
|
g_free (my_second);
|
1998-02-27 07:54:42 +03:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* If filename is NULL, then we just append PATH_SEP to the dir
|
|
|
|
*/
|
|
|
|
|
2009-02-06 13:17:03 +03:00
|
|
|
char *
|
|
|
|
concat_dir_and_file (const char *dir, const char *file)
|
|
|
|
{
|
|
|
|
int i = strlen (dir);
|
2010-02-26 12:25:53 +03:00
|
|
|
|
|
|
|
if (dir[i - 1] == PATH_SEP)
|
|
|
|
return g_strconcat (dir, file, (char *) NULL);
|
2009-02-06 13:17:03 +03:00
|
|
|
else
|
2010-02-26 12:25:53 +03:00
|
|
|
return g_strconcat (dir, PATH_SEP_STR, file, (char *) NULL);
|
2009-02-06 13:17:03 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* Append text to GList, remove all entries with the same text
|
|
|
|
*/
|
|
|
|
|
2003-02-18 09:12:57 +03:00
|
|
|
GList *
|
2010-02-26 12:25:53 +03:00
|
|
|
list_append_unique (GList * list, char *text)
|
2003-02-18 09:12:57 +03:00
|
|
|
{
|
2010-01-08 12:47:43 +03:00
|
|
|
GList *lc_link;
|
2003-02-18 09:12:57 +03:00
|
|
|
|
2003-02-19 02:21:54 +03:00
|
|
|
/*
|
|
|
|
* Go to the last position and traverse the list backwards
|
|
|
|
* starting from the second last entry to make sure that we
|
|
|
|
* are not removing the current link.
|
|
|
|
*/
|
|
|
|
list = g_list_append (list, text);
|
|
|
|
list = g_list_last (list);
|
2009-10-30 04:12:04 +03:00
|
|
|
lc_link = g_list_previous (list);
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
while (lc_link != NULL)
|
|
|
|
{
|
|
|
|
GList *newlink;
|
2010-01-08 12:47:43 +03:00
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
newlink = g_list_previous (lc_link);
|
|
|
|
if (strcmp ((char *) lc_link->data, text) == 0)
|
|
|
|
{
|
|
|
|
GList *tmp;
|
2010-01-08 12:47:43 +03:00
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
g_free (lc_link->data);
|
|
|
|
tmp = g_list_remove_link (list, lc_link);
|
|
|
|
g_list_free_1 (lc_link);
|
|
|
|
}
|
|
|
|
lc_link = newlink;
|
2003-02-18 09:12:57 +03:00
|
|
|
}
|
|
|
|
|
2003-02-19 02:21:54 +03:00
|
|
|
return list;
|
2003-02-18 09:12:57 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2001-05-21 20:21:07 +04:00
|
|
|
/* Following code heavily borrows from libiberty, mkstemps.c */
|
|
|
|
/*
|
|
|
|
* Arguments:
|
2009-02-06 01:27:37 +03:00
|
|
|
* pname (output) - pointer to the name of the temp file (needs g_free).
|
2001-05-22 11:10:43 +04:00
|
|
|
* NULL if the function fails.
|
2001-07-27 23:27:09 +04:00
|
|
|
* prefix - part of the filename before the random part.
|
|
|
|
* Prepend $TMPDIR or /tmp if there are no path separators.
|
2001-05-22 11:10:43 +04:00
|
|
|
* suffix - if not NULL, part of the filename after the random part.
|
2001-05-21 20:21:07 +04:00
|
|
|
*
|
|
|
|
* Result:
|
|
|
|
* handle of the open file or -1 if couldn't open any.
|
|
|
|
*/
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2002-11-01 23:24:07 +03:00
|
|
|
int
|
|
|
|
mc_mkstemps (char **pname, const char *prefix, const char *suffix)
|
2001-05-21 20:21:07 +04:00
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
2001-07-17 22:38:46 +04:00
|
|
|
static unsigned long value;
|
2001-05-21 20:21:07 +04:00
|
|
|
struct timeval tv;
|
|
|
|
char *tmpbase;
|
|
|
|
char *tmpname;
|
|
|
|
char *XXXXXX;
|
|
|
|
int count;
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
if (strchr (prefix, PATH_SEP) == NULL)
|
|
|
|
{
|
|
|
|
/* Add prefix first to find the position of XXXXXX */
|
|
|
|
tmpbase = concat_dir_and_file (mc_tmpdir (), prefix);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmpbase = g_strdup (prefix);
|
2001-07-27 23:27:09 +04:00
|
|
|
}
|
2001-05-21 20:21:07 +04:00
|
|
|
|
2004-09-24 19:05:28 +04:00
|
|
|
tmpname = g_strconcat (tmpbase, "XXXXXX", suffix, (char *) NULL);
|
2001-05-22 11:10:43 +04:00
|
|
|
*pname = tmpname;
|
2001-05-21 20:21:07 +04:00
|
|
|
XXXXXX = &tmpname[strlen (tmpbase)];
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (tmpbase);
|
2001-05-21 20:21:07 +04:00
|
|
|
|
|
|
|
/* Get some more or less random data. */
|
|
|
|
gettimeofday (&tv, NULL);
|
|
|
|
value += (tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
for (count = 0; count < TMP_MAX; ++count)
|
|
|
|
{
|
|
|
|
unsigned long v = value;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
/* Fill in the random bits. */
|
|
|
|
XXXXXX[0] = letters[v % 62];
|
|
|
|
v /= 62;
|
|
|
|
XXXXXX[1] = letters[v % 62];
|
|
|
|
v /= 62;
|
|
|
|
XXXXXX[2] = letters[v % 62];
|
|
|
|
v /= 62;
|
|
|
|
XXXXXX[3] = letters[v % 62];
|
|
|
|
v /= 62;
|
|
|
|
XXXXXX[4] = letters[v % 62];
|
|
|
|
v /= 62;
|
|
|
|
XXXXXX[5] = letters[v % 62];
|
|
|
|
|
|
|
|
fd = open (tmpname, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, S_IRUSR | S_IWUSR);
|
|
|
|
if (fd >= 0)
|
|
|
|
{
|
|
|
|
/* Successfully created. */
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is a random value. It is only necessary that the next
|
|
|
|
TMP_MAX values generated by adding 7777 to VALUE are different
|
|
|
|
with (module 2^32). */
|
|
|
|
value += 7777;
|
2001-05-21 20:21:07 +04:00
|
|
|
}
|
|
|
|
|
2001-05-22 11:10:43 +04:00
|
|
|
/* Unsuccessful. Free the filename. */
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (tmpname);
|
2002-09-27 02:13:16 +04:00
|
|
|
*pname = NULL;
|
2001-05-21 20:21:07 +04:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2002-12-08 09:51:22 +03:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
2002-12-08 09:51:22 +03:00
|
|
|
* Read and restore position for the given filename.
|
|
|
|
* If there is no stored data, return line 1 and col 0.
|
|
|
|
*/
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2002-12-08 09:51:22 +03:00
|
|
|
void
|
2010-11-08 13:21:45 +03:00
|
|
|
load_file_position (const char *filename, long *line, long *column, off_t * offset,
|
|
|
|
GArray ** bookmarks)
|
2002-12-08 09:51:22 +03:00
|
|
|
{
|
|
|
|
char *fn;
|
|
|
|
FILE *f;
|
2010-07-17 20:21:29 +04:00
|
|
|
char buf[MC_MAXPATHLEN + 100];
|
2010-09-07 10:29:25 +04:00
|
|
|
const size_t len = strlen (filename);
|
2002-12-08 09:51:22 +03:00
|
|
|
|
|
|
|
/* defaults */
|
|
|
|
*line = 1;
|
|
|
|
*column = 0;
|
2010-01-12 14:51:01 +03:00
|
|
|
*offset = 0;
|
2002-12-08 09:51:22 +03:00
|
|
|
|
|
|
|
/* open file with positions */
|
2011-11-24 02:28:07 +04:00
|
|
|
fn = mc_config_get_full_path (MC_FILEPOS_FILE);
|
2002-12-08 09:51:22 +03:00
|
|
|
f = fopen (fn, "r");
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (fn);
|
2010-09-07 10:29:25 +04:00
|
|
|
if (f == NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
return;
|
2002-12-08 09:51:22 +03:00
|
|
|
|
2010-07-17 20:21:29 +04:00
|
|
|
/* prepare array for serialized bookmarks */
|
2010-09-07 16:05:24 +04:00
|
|
|
*bookmarks = g_array_sized_new (FALSE, FALSE, sizeof (size_t), MAX_SAVED_BOOKMARKS);
|
2002-12-08 09:51:22 +03:00
|
|
|
|
2010-09-07 10:29:25 +04:00
|
|
|
while (fgets (buf, sizeof (buf), f) != NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
gchar **pos_tokens;
|
|
|
|
|
|
|
|
/* check if the filename matches the beginning of string */
|
|
|
|
if (strncmp (buf, filename, len) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* followed by single space */
|
|
|
|
if (buf[len] != ' ')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* and string without spaces */
|
|
|
|
p = &buf[len + 1];
|
2010-09-07 10:29:25 +04:00
|
|
|
if (strchr (p, ' ') != NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
continue;
|
|
|
|
|
2010-09-07 10:29:25 +04:00
|
|
|
pos_tokens = g_strsplit (p, ";", 3 + MAX_SAVED_BOOKMARKS);
|
|
|
|
if (pos_tokens[0] == NULL)
|
|
|
|
{
|
|
|
|
*line = 1;
|
|
|
|
*column = 0;
|
|
|
|
*offset = 0;
|
|
|
|
}
|
|
|
|
else
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
|
|
|
*line = strtol (pos_tokens[0], NULL, 10);
|
2010-09-07 10:29:25 +04:00
|
|
|
if (pos_tokens[1] == NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
2010-09-07 10:29:25 +04:00
|
|
|
*column = 0;
|
|
|
|
*offset = 0;
|
2010-02-26 12:25:53 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*column = strtol (pos_tokens[1], NULL, 10);
|
2010-09-07 10:29:25 +04:00
|
|
|
if (pos_tokens[2] == NULL)
|
|
|
|
*offset = 0;
|
|
|
|
else
|
2010-07-17 20:21:29 +04:00
|
|
|
{
|
2010-09-07 10:29:25 +04:00
|
|
|
size_t i;
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
*offset = strtoll (pos_tokens[2], NULL, 10);
|
2010-09-07 10:29:25 +04:00
|
|
|
|
2010-09-07 16:05:24 +04:00
|
|
|
for (i = 0; i < MAX_SAVED_BOOKMARKS && pos_tokens[3 + i] != NULL; i++)
|
2010-07-17 20:21:29 +04:00
|
|
|
{
|
2010-09-07 16:05:24 +04:00
|
|
|
size_t val;
|
|
|
|
|
|
|
|
val = strtoul (pos_tokens[3 + i], NULL, 10);
|
|
|
|
g_array_append_val (*bookmarks, val);
|
2010-07-17 20:21:29 +04:00
|
|
|
}
|
|
|
|
}
|
2010-02-26 12:25:53 +03:00
|
|
|
}
|
|
|
|
}
|
2010-09-07 10:29:25 +04:00
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
g_strfreev (pos_tokens);
|
2002-12-08 09:51:22 +03:00
|
|
|
}
|
2010-09-07 10:29:25 +04:00
|
|
|
|
2002-12-08 09:51:22 +03:00
|
|
|
fclose (f);
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* Save position for the given file
|
|
|
|
*/
|
|
|
|
|
2002-12-08 09:51:22 +03:00
|
|
|
void
|
2010-11-08 13:21:45 +03:00
|
|
|
save_file_position (const char *filename, long line, long column, off_t offset, GArray * bookmarks)
|
2002-12-08 09:51:22 +03:00
|
|
|
{
|
2010-09-07 16:05:24 +04:00
|
|
|
static size_t filepos_max_saved_entries = 0;
|
2009-10-20 00:40:28 +04:00
|
|
|
char *fn, *tmp_fn;
|
|
|
|
FILE *f, *tmp_f;
|
2010-07-17 20:21:29 +04:00
|
|
|
char buf[MC_MAXPATHLEN + 100];
|
2010-09-07 16:05:24 +04:00
|
|
|
size_t i;
|
2010-09-07 10:29:25 +04:00
|
|
|
const size_t len = strlen (filename);
|
|
|
|
gboolean src_error = FALSE;
|
2009-10-20 00:40:28 +04:00
|
|
|
|
|
|
|
if (filepos_max_saved_entries == 0)
|
2010-07-17 20:21:29 +04:00
|
|
|
filepos_max_saved_entries = mc_config_get_int (mc_main_config, CONFIG_APP_SECTION,
|
|
|
|
"filepos_max_saved_entries", 1024);
|
2002-12-08 09:51:22 +03:00
|
|
|
|
2011-11-24 02:28:07 +04:00
|
|
|
fn = mc_config_get_full_path (MC_FILEPOS_FILE);
|
2009-10-05 18:32:46 +04:00
|
|
|
if (fn == NULL)
|
2010-01-11 00:53:22 +03:00
|
|
|
goto early_error;
|
2009-10-05 18:32:46 +04:00
|
|
|
|
2009-10-20 00:40:28 +04:00
|
|
|
mc_util_make_backup_if_possible (fn, TMP_SUFFIX);
|
2002-12-08 09:51:22 +03:00
|
|
|
|
2009-10-05 18:32:46 +04:00
|
|
|
/* open file */
|
2009-10-20 00:40:28 +04:00
|
|
|
f = fopen (fn, "w");
|
2010-01-11 00:53:22 +03:00
|
|
|
if (f == NULL)
|
|
|
|
goto open_target_error;
|
2002-12-08 09:51:22 +03:00
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
tmp_fn = g_strdup_printf ("%s" TMP_SUFFIX, fn);
|
2009-10-20 00:40:28 +04:00
|
|
|
tmp_f = fopen (tmp_fn, "r");
|
2010-01-11 00:53:22 +03:00
|
|
|
if (tmp_f == NULL)
|
2010-09-07 10:29:25 +04:00
|
|
|
{
|
|
|
|
src_error = TRUE;
|
2010-01-11 00:53:22 +03:00
|
|
|
goto open_source_error;
|
2010-09-07 10:29:25 +04:00
|
|
|
}
|
2009-10-20 00:40:28 +04:00
|
|
|
|
2002-12-08 09:51:22 +03:00
|
|
|
/* put the new record */
|
2010-07-17 20:21:29 +04:00
|
|
|
if (line != 1 || column != 0 || bookmarks != NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
2010-12-02 21:50:57 +03:00
|
|
|
if (fprintf (f, "%s %ld;%ld;%" PRIuMAX, filename, line, column, (uintmax_t) offset) < 0)
|
2010-07-17 20:21:29 +04:00
|
|
|
goto write_position_error;
|
|
|
|
if (bookmarks != NULL)
|
2010-09-07 16:05:24 +04:00
|
|
|
for (i = 0; i < bookmarks->len && i < MAX_SAVED_BOOKMARKS; i++)
|
|
|
|
if (fprintf (f, ";%zu", g_array_index (bookmarks, size_t, i)) < 0)
|
2010-07-17 20:21:29 +04:00
|
|
|
goto write_position_error;
|
2010-09-07 10:29:25 +04:00
|
|
|
|
2010-07-17 20:21:29 +04:00
|
|
|
if (fprintf (f, "\n") < 0)
|
2010-01-11 00:53:22 +03:00
|
|
|
goto write_position_error;
|
2009-10-09 02:15:03 +04:00
|
|
|
}
|
2002-12-08 09:51:22 +03:00
|
|
|
|
2010-07-17 20:21:29 +04:00
|
|
|
i = 1;
|
2010-09-07 10:29:25 +04:00
|
|
|
while (fgets (buf, sizeof (buf), tmp_f) != NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
{
|
2010-11-08 13:21:45 +03:00
|
|
|
if (buf[len] == ' ' && strncmp (buf, filename, len) == 0
|
|
|
|
&& strchr (&buf[len + 1], ' ') == NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
fprintf (f, "%s", buf);
|
|
|
|
if (++i > filepos_max_saved_entries)
|
|
|
|
break;
|
2009-10-20 00:40:28 +04:00
|
|
|
}
|
2010-01-11 00:53:22 +03:00
|
|
|
|
|
|
|
write_position_error:
|
|
|
|
fclose (tmp_f);
|
|
|
|
open_source_error:
|
2010-02-26 12:25:53 +03:00
|
|
|
g_free (tmp_fn);
|
2010-01-11 00:53:22 +03:00
|
|
|
fclose (f);
|
2010-09-07 10:29:25 +04:00
|
|
|
if (src_error)
|
|
|
|
mc_util_restore_from_backup_if_possible (fn, TMP_SUFFIX);
|
|
|
|
else
|
|
|
|
mc_util_unlink_backup_if_possible (fn, TMP_SUFFIX);
|
2010-01-11 00:53:22 +03:00
|
|
|
open_target_error:
|
|
|
|
g_free (fn);
|
|
|
|
early_error:
|
2010-11-09 14:05:11 +03:00
|
|
|
if (bookmarks != NULL)
|
|
|
|
g_array_free (bookmarks, TRUE);
|
2002-12-08 09:51:22 +03:00
|
|
|
}
|
2010-02-26 12:25:53 +03:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-07-18 13:31:37 +04:00
|
|
|
extern int
|
|
|
|
ascii_alpha_to_cntrl (int ch)
|
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
if ((ch >= ASCII_A && ch <= ASCII_Z) || (ch >= ASCII_a && ch <= ASCII_z))
|
|
|
|
{
|
|
|
|
ch &= 0x1f;
|
2005-07-18 13:31:37 +04:00
|
|
|
}
|
|
|
|
return ch;
|
|
|
|
}
|
2005-11-03 05:18:38 +03:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2005-11-03 05:18:38 +03:00
|
|
|
const char *
|
|
|
|
Q_ (const char *s)
|
|
|
|
{
|
|
|
|
const char *result, *sep;
|
|
|
|
|
|
|
|
result = _(s);
|
2010-02-26 12:25:53 +03:00
|
|
|
sep = strchr (result, '|');
|
2005-11-03 05:18:38 +03:00
|
|
|
return (sep != NULL) ? sep + 1 : result;
|
|
|
|
}
|
2009-02-06 13:17:03 +03:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2009-10-05 18:32:46 +04:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
mc_util_make_backup_if_possible (const char *file_name, const char *backup_suffix)
|
|
|
|
{
|
|
|
|
struct stat stat_buf;
|
|
|
|
char *backup_path;
|
|
|
|
gboolean ret;
|
|
|
|
if (!exist_file (file_name))
|
2010-02-26 12:25:53 +03:00
|
|
|
return FALSE;
|
2009-10-05 18:32:46 +04:00
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
|
2009-10-05 18:32:46 +04:00
|
|
|
|
|
|
|
if (backup_path == NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
return FALSE;
|
2009-10-05 18:32:46 +04:00
|
|
|
|
|
|
|
ret = mc_util_write_backup_content (file_name, backup_path);
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
/* Backup file will have same ownership with main file. */
|
|
|
|
if (stat (file_name, &stat_buf) == 0)
|
|
|
|
chmod (backup_path, stat_buf.st_mode);
|
|
|
|
else
|
|
|
|
chmod (backup_path, S_IRUSR | S_IWUSR);
|
2009-10-05 18:32:46 +04:00
|
|
|
}
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
g_free (backup_path);
|
2009-10-05 18:32:46 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-10-05 18:32:46 +04:00
|
|
|
gboolean
|
|
|
|
mc_util_restore_from_backup_if_possible (const char *file_name, const char *backup_suffix)
|
|
|
|
{
|
|
|
|
gboolean ret;
|
|
|
|
char *backup_path;
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
|
2009-10-05 18:32:46 +04:00
|
|
|
if (backup_path == NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
return FALSE;
|
2009-10-05 18:32:46 +04:00
|
|
|
|
|
|
|
ret = mc_util_write_backup_content (backup_path, file_name);
|
2010-02-26 12:25:53 +03:00
|
|
|
g_free (backup_path);
|
2009-10-05 18:32:46 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-10-05 18:32:46 +04:00
|
|
|
gboolean
|
|
|
|
mc_util_unlink_backup_if_possible (const char *file_name, const char *backup_suffix)
|
|
|
|
{
|
|
|
|
char *backup_path;
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
|
2009-10-05 18:32:46 +04:00
|
|
|
if (backup_path == NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
return FALSE;
|
2009-10-05 18:32:46 +04:00
|
|
|
|
|
|
|
if (exist_file (backup_path))
|
2011-07-21 01:22:50 +04:00
|
|
|
{
|
|
|
|
vfs_path_t *vpath;
|
|
|
|
|
|
|
|
vpath = vfs_path_from_str (backup_path);
|
|
|
|
mc_unlink (vpath);
|
|
|
|
vfs_path_free (vpath);
|
|
|
|
}
|
2009-10-05 18:32:46 +04:00
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
g_free (backup_path);
|
2009-10-05 18:32:46 +04:00
|
|
|
return TRUE;
|
|
|
|
}
|
2010-01-21 13:30:08 +03:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* partly taken from dcigettext.c, returns "" for default locale
|
|
|
|
* value should be freed by calling function g_free()
|
|
|
|
*/
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
char *
|
|
|
|
guess_message_value (void)
|
2010-01-21 13:30:08 +03:00
|
|
|
{
|
2010-02-26 12:25:53 +03:00
|
|
|
static const char *const var[] = {
|
|
|
|
/* Setting of LC_ALL overwrites all other. */
|
|
|
|
/* Do not use LANGUAGE for check user locale and drowing hints */
|
|
|
|
"LC_ALL",
|
|
|
|
/* Next comes the name of the desired category. */
|
|
|
|
"LC_MESSAGES",
|
2010-01-21 13:30:08 +03:00
|
|
|
/* Last possibility is the LANG environment variable. */
|
2010-02-26 12:25:53 +03:00
|
|
|
"LANG",
|
|
|
|
/* NULL exit loops */
|
|
|
|
NULL
|
2010-01-21 13:30:08 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
unsigned i = 0;
|
|
|
|
const char *locale = NULL;
|
|
|
|
|
2010-02-26 12:25:53 +03:00
|
|
|
while (var[i] != NULL)
|
|
|
|
{
|
|
|
|
locale = getenv (var[i]);
|
|
|
|
if (locale != NULL && locale[0] != '\0')
|
|
|
|
break;
|
|
|
|
i++;
|
2010-01-21 13:30:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (locale == NULL)
|
2010-02-26 12:25:53 +03:00
|
|
|
locale = "";
|
2010-01-21 13:30:08 +03:00
|
|
|
|
|
|
|
return g_strdup (locale);
|
|
|
|
}
|
2010-11-08 13:21:45 +03:00
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|