mc/src/util.c

1412 lines
32 KiB
C
Raw Normal View History

1998-02-27 07:54:42 +03:00
/* Various utilities
Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
Written 1994, 1995, 1996 by:
Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
Jakub Jelinek, Mauricio Plaza.
The file_date routine is mostly from GNU's fileutils package,
written by Richard Stallman and David MacKenzie.
This program 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 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
1998-02-27 07:54:42 +03:00
#include <config.h>
#include <stdio.h>
#if defined(NEEDS_IO_H) /* OS/2 need io.h! .ado */
1998-02-27 07:54:42 +03:00
# include <io.h>
#endif
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <signal.h> /* my_system */
#include <limits.h> /* INT_MAX */
#ifndef SCO_FLAVOR
# include <sys/time.h> /* alex: sys/select.h defines struct timeval */
#endif /* SCO_FLAVOR */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <errno.h> /* my_system */
#ifdef SCO_FLAVOR
# include <sys/timeb.h> /* alex: for struct timeb, used in time.h */
#endif /* SCO_FLAVOR */
#include <time.h>
#ifndef HAS_NO_GRP_PWD_H
1998-02-27 07:54:42 +03:00
# include <pwd.h>
# include <grp.h>
#endif
#include <string.h>
#include <ctype.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef __linux__
# if defined(__GLIBC__) && (__GLIBC__ < 2)
# include <linux/termios.h> /* This is needed for TIOCLINUX */
# else
# include <termios.h>
# endif
# include <sys/ioctl.h>
#endif
#include "mountlist.h"
#if defined(HAVE_RX_H) && defined(HAVE_REGCOMP)
#include <rx.h>
#else
#include <regex.h>
1998-02-27 07:54:42 +03:00
#endif
#include "global.h"
#include "x.h"
1998-02-27 07:54:42 +03:00
#include "profile.h"
#include "main.h" /* mc_home */
#include "cmd.h" /* guess_message_value */
1998-02-27 07:54:42 +03:00
#include "../vfs/vfs.h"
#ifdef HAVE_CHARSET
#include "charsets.h"
#endif
1998-02-27 07:54:42 +03:00
/* "$Id$" */
char app_text [] = "Midnight-Commander";
int easy_patterns = 1;
int align_extensions = 1;
int tilde_trunc = 1;
#ifndef VFS_STANDALONE
1998-02-27 07:54:42 +03:00
int is_printable (int c)
{
#ifndef HAVE_X
1998-02-27 07:54:42 +03:00
static const unsigned char xterm_printable[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
};
extern int xterm_flag;
c &= 0xff;
#ifdef HAVE_CHARSET
if (display_codepage < 0) {
if (xterm_flag)
return xterm_printable[c];
else
return (c > 31 && c != 127 && c != 155);
} else
return printable[ c ];
#else
1998-02-27 07:54:42 +03:00
if (eight_bit_clean){
if (full_eight_bits){
if (xterm_flag)
return xterm_printable [c];
else
return (c > 31 && c != 127 && c != 155);
1998-02-27 07:54:42 +03:00
} else
return ((c >31 && c < 127) || c >= 160);
} else
return (c > 31 && c < 127);
#endif /* !HAVE_CHARSET */
#else
return 1;
#endif /* HAVE_X */
1998-02-27 07:54:42 +03:00
}
/* Returns the message dimensions (lines and columns) */
int msglen (char *text, int *lines)
{
int max = 0;
int line_len = 0;
for (*lines = 1;*text; text++){
if (*text == '\n'){
line_len = 0;
(*lines)++;
} else {
line_len++;
if (line_len > max)
max = line_len;
}
}
return max;
}
char *trim (char *s, char *d, int len)
{
int source_len = strlen (s);
if (source_len > len){
strcpy (d, s+(source_len-len));
d [0] = '.';
d [1] = '.';
d [2] = '.';
} else
strcpy (d, s);
return d;
}
#endif /* !VFS_STANDALONE */
1998-02-27 07:54:42 +03:00
char *
name_quote (const char *s, int quote_percent)
{
char *ret, *d;
d = ret = g_malloc (strlen (s)*2 + 2 + 1);
1998-02-27 07:54:42 +03:00
if (*s == '-') {
*d++ = '.';
*d++ = '/';
}
for (; *s; s++, d++) {
switch (*s)
{
case '%':
if (quote_percent)
*d++ = '%';
break;
case '\'':
case '\\':
case '\r':
case '\n':
case '\t':
case '"':
case ':':
case ';':
case ' ':
1998-02-27 07:54:42 +03:00
case '?':
case '|':
1998-02-27 07:54:42 +03:00
case '[':
case ']':
case '{':
case '}':
case '<':
case '>':
case '`':
case '~':
1998-02-27 07:54:42 +03:00
case '!':
case '@':
1998-02-27 07:54:42 +03:00
case '#':
case '$':
case '^':
case '&':
case '*':
case '(':
case ')':
1998-02-27 07:54:42 +03:00
*d++ = '\\';
}
*d = *s;
}
*d = '\0';
return ret;
}
#ifndef VFS_STANDALONE
1998-02-27 07:54:42 +03:00
char *
fake_name_quote (const char *s, int quote_percent)
{
return g_strdup (s);
1998-02-27 07:54:42 +03:00
}
/* If passed an empty txt (this usually means that there is an error)
* in the upper layers, we return "/"
*/
char *name_trunc (char *txt, int trunc_len)
{
static char x [MC_MAXPATHLEN+MC_MAXPATHLEN];
int txt_len;
char *p;
if (!txt)
txt = PATH_SEP_STR;
if (trunc_len > sizeof (x)-1){
fprintf (stderr, _("name_trunc: too big"));
1998-02-27 07:54:42 +03:00
trunc_len = sizeof (x)-1;
}
txt_len = strlen (txt);
if (txt_len <= trunc_len)
strcpy (x, txt);
else if (tilde_trunc){
int y = (trunc_len/2) + (trunc_len % 2);
strncpy (x, txt, y);
strncpy (x+y, txt+txt_len-(trunc_len/2), trunc_len/2);
x [y] = '~';
1998-02-27 07:54:42 +03:00
} else {
strncpy (x, txt, trunc_len-1);
x [trunc_len-1] = '>';
}
x [trunc_len] = 0;
for (p = x; *p; p++)
if (!is_printable (*p))
*p = '?';
return x;
}
char *size_trunc (double size)
1998-02-27 07:54:42 +03:00
{
static char x [BUF_TINY];
1998-02-27 07:54:42 +03:00
long int divisor = 1;
char *xtra = "";
if (size > 999999999L){
divisor = 1024;
xtra = "Kb";
1998-02-27 07:54:42 +03:00
if (size/divisor > 999999999L){
divisor = 1024*1024;
xtra = "Mb";
}
}
g_snprintf (x, sizeof (x), "%.0f%s", (size/divisor), xtra);
1998-02-27 07:54:42 +03:00
return x;
}
char *size_trunc_sep (double size)
1998-02-27 07:54:42 +03:00
{
static char x [60];
int count;
char *p, *d, *y;
p = y = size_trunc (size);
p += strlen (p) - 1;
d = x + sizeof (x) - 1;
*d-- = 0;
while (p >= y && isalpha (*p))
*d-- = *p--;
for (count = 0; p >= y; count++){
if (count == 3){
*d-- = ',';
count = 0;
}
*d-- = *p--;
}
d++;
if (*d == ',')
d++;
return d;
}
/*
* 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.
*/
void
size_trunc_len (char *buffer, int len, off_t size)
{
/* Avoid taking power for every file. */
static const off_t power10 [] =
{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
1000000000};
static const char * const suffix [] =
{"", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL};
int j = 0;
/* Don't print more than 9 digits - use suffix. */
if (len == 0 || len > 9)
len = 9;
for (j = 0; suffix [j] != NULL; j++) {
if (size < power10 [len - (j > 0)]) {
g_snprintf (buffer, len + 1, "%lu%s", (unsigned long) size, suffix[j]);
break;
}
/* Powers of 1024, no rounding. */
size = size >> 10;
}
}
1998-02-27 07:54:42 +03:00
int is_exe (mode_t mode)
{
if ((S_IXUSR & mode) || (S_IXGRP & mode) || (S_IXOTH & mode))
return 1;
return 0;
}
#define ismode(n,m) ((n & m) == m)
char *string_perm (mode_t mode_bits)
{
static char mode [11];
strcpy (mode, "----------");
if (ismode (mode_bits, S_IFDIR)) mode [0] = 'd';
#ifdef S_IFSOCK
if (ismode (mode_bits, S_IFSOCK)) mode [0] = 's';
#endif /* S_IFSOCK */
1998-02-27 07:54:42 +03:00
if (ismode (mode_bits, S_IXOTH)) mode [9] = 'x';
if (ismode (mode_bits, S_IWOTH)) mode [8] = 'w';
if (ismode (mode_bits, S_IROTH)) mode [7] = 'r';
if (ismode (mode_bits, S_IXGRP)) mode [6] = 'x';
if (ismode (mode_bits, S_IWGRP)) mode [5] = 'w';
if (ismode (mode_bits, S_IRGRP)) mode [4] = 'r';
if (ismode (mode_bits, S_IXUSR)) mode [3] = 'x';
if (ismode (mode_bits, S_IWUSR)) mode [2] = 'w';
if (ismode (mode_bits, S_IRUSR)) mode [1] = 'r';
#ifndef OS2_NT
1998-02-27 07:54:42 +03:00
if (ismode (mode_bits, S_ISUID)) mode [3] = (mode [3] == 'x') ? 's' : 'S';
if (ismode (mode_bits, S_ISGID)) mode [6] = (mode [6] == 'x') ? 's' : 'S';
if (ismode (mode_bits, S_IFCHR)) mode [0] = 'c';
if (ismode (mode_bits, S_IFBLK)) mode [0] = 'b';
if (ismode (mode_bits, S_ISVTX)) mode [9] = (mode [9] == 'x') ? 't' : 'T';
if (ismode (mode_bits, S_IFLNK)) mode [0] = 'l';
1999-09-19 Andrew V. Samoilov <sav@bcs.zp.ua> * src/user.c (check_patterns): char* is used instead of char [] in sizeof * src/util.c (string_perm): prefix named pipes by 'p' and not by `s' 1999-09-19 David Martin <dmartina@usa.net> * gtkedit/editcmd.c (edit_print_string): Use unsigned char so that 8 bit chars from strftime get displayed when inserting date. * lib/mc.ext.in: Add entries for bzip2 compressed pages as used in Mandrake 6.0. The generic entry for bzip2 moved to the end of the file to avoid interferences. In this one I changed the extension check to a type check (as used for gzip) which might give problems in some systems. * configure.in: Use -Tlatin1 to format man pages when available and "view" 8 bit chars. 1999-09-19 Norbert Warmuth <nwarmuth@privat.circular.de> * gtkedit/edit.h: Include files reordered in order to make it compile with --with-debug * gtkedit/editcmd.c (menu_save_mode_cmd): calculate dialog width dependent on lenght of translated strings to display. * src/mad.c, mad.h, util.c, util.h: Move mad-functions from util.[ch] to mad.[ch] * src/option.c: Include files reordered in order to make it compile with --with-debug * src/mad.c (mad_init): New function. Initialize debug FILE pointer to stderr (moved to a function because not on every system stderr is a constant). (mad_set_debug): added const qualifier * src/main.c (main): call mad_init * po/*.po: s/defination/definition/ * gnome/Makefile.in ($(MAGICDEV_GENERATED)): Make it compile with $buildir != $srcdir. * vfs/ftpfs.c (ftpfs_set_debug), vfs.h: added const qualifier. * vfs/mcserv.c: removed definition of mad_strconcat which is also in mad.c.
1999-09-20 03:09:07 +04:00
if (ismode (mode_bits, S_IFIFO)) mode [0] = 'p';
#endif /* !OS2_NT */
1998-02-27 07:54:42 +03:00
return mode;
}
/* 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.
Cavevat: only the first url is found
*/
char *
strip_password (char *p, int has_prefix)
1998-02-27 07:54:42 +03:00
{
static const struct {
char *name;
size_t len;
} prefixes[] = { {"/#ftp:", 6},
{"/#mc:", 5},
{"ftp://", 6},
{"/#smb:", 6},
};
1998-02-27 07:54:42 +03:00
char *at, *inner_colon, *dir;
int i;
char *result = p;
1998-02-27 07:54:42 +03:00
for (i = 0; i < sizeof (prefixes)/sizeof (prefixes[0]); i++) {
char *q;
if (has_prefix) {
if((q = strstr (p, prefixes[i].name)) == 0)
continue;
else
p = q + prefixes[i].len;
};
if ((dir = strchr (p, PATH_SEP)) != NULL)
*dir = '\0';
/* search for any possible user */
at = strchr (p, '@');
/* We have a username */
if (at) {
*at = 0;
inner_colon = strchr (p, ':');
*at = '@';
if (inner_colon)
strcpy (inner_colon, at);
}
if (dir)
*dir = PATH_SEP;
break;
1998-02-27 07:54:42 +03:00
}
return (result);
1998-02-27 07:54:42 +03:00
}
char *strip_home_and_password(char *dir)
{
size_t len;
static char newdir [MC_MAXPATHLEN];
1998-02-27 07:54:42 +03:00
if (home_dir && !strncmp (dir, home_dir, len = strlen (home_dir)) &&
(dir[len] == PATH_SEP || dir[len] == '\0')){
1998-02-27 07:54:42 +03:00
newdir [0] = '~';
strcpy (&newdir [1], &dir [strlen (home_dir)]);
return newdir;
}
/* We do not strip homes in /#ftp tree, I do not like ~'s there
(see ftpfs.c why) */
strcpy (newdir, dir);
strip_password (newdir, 1);
return newdir;
1998-02-27 07:54:42 +03:00
}
static char *maybe_start_group (char *d, int do_group, int *was_wildcard)
{
if (!do_group)
return d;
if (*was_wildcard)
return d;
*was_wildcard = 1;
*d++ = '\\';
*d++ = '(';
return d;
}
static char *maybe_end_group (char *d, int do_group, int *was_wildcard)
{
if (!do_group)
return d;
if (!*was_wildcard)
return d;
*was_wildcard = 0;
*d++ = '\\';
*d++ = ')';
return d;
}
/* If shell patterns are on converts a shell pattern to a regular
expression. Called by regexp_match and mask_rename. */
/* Shouldn't we support [a-fw] type wildcards as well ?? */
char *convert_pattern (char *pattern, int match_type, int do_group)
{
char *s, *d;
char *new_pattern;
1998-02-27 07:54:42 +03:00
int was_wildcard = 0;
if (easy_patterns){
new_pattern = g_malloc (MC_MAXPATHLEN);
1998-02-27 07:54:42 +03:00
d = new_pattern;
if (match_type == match_file)
*d++ = '^';
for (s = pattern; *s; s++, d++){
switch (*s){
case '*':
d = maybe_start_group (d, do_group, &was_wildcard);
*d++ = '.';
*d = '*';
break;
case '?':
d = maybe_start_group (d, do_group, &was_wildcard);
*d = '.';
break;
case '.':
d = maybe_end_group (d, do_group, &was_wildcard);
*d++ = '\\';
*d = '.';
break;
default:
d = maybe_end_group (d, do_group, &was_wildcard);
*d = *s;
break;
}
}
d = maybe_end_group (d, do_group, &was_wildcard);
if (match_type == match_file)
*d++ = '$';
*d = 0;
return new_pattern;
} else
return g_strdup (pattern);
1998-02-27 07:54:42 +03:00
}
int regexp_match (char *pattern, char *string, int match_type)
{
static regex_t r;
static char *old_pattern = NULL;
static int old_type;
int rval;
if (!old_pattern || STRCOMP (old_pattern, pattern) || old_type != match_type){
if (old_pattern){
regfree (&r);
g_free (old_pattern);
old_pattern = NULL;
1998-02-27 07:54:42 +03:00
}
pattern = convert_pattern (pattern, match_type, 0);
if (regcomp (&r, pattern, REG_EXTENDED|REG_NOSUB|MC_ARCH_FLAGS)) {
g_free (pattern);
1998-02-27 07:54:42 +03:00
return -1;
}
old_pattern = pattern;
1998-02-27 07:54:42 +03:00
old_type = match_type;
}
rval = !regexec (&r, string, 0, NULL, 0);
return rval;
}
char *extension (char *filename)
{
char *d;
if (!(*filename))
1998-02-27 07:54:42 +03:00
return "";
d = filename + strlen (filename) - 1;
for (;d >= filename; d--){
if (*d == '.')
return d+1;
}
return "";
}
/* This routine uses the fact that x is at most 14 chars or so */
char *split_extension (char *x, int pad)
{
return x;
/* Buggy code
if (!align_extensions)
return x;
if (strlen (x) >= pad)
return x;
if ((ext = extension (x)) == x || *ext == 0)
return x;
strcpy (xbuf, x);
for (i = strlen (x); i < pad; i++)
xbuf [i] = ' ';
xbuf [pad] = 0;
l = strlen (ext);
for (i = 0; i < l; i++)
xbuf [pad-i] = *(ext+l-i-1);
for (i = xbuf + (ext - x); i <
return xbuf; */
}
int get_int (char *file, char *key, int def)
{
return GetPrivateProfileInt (app_text, key, def, file);
}
int set_int (char *file, char *key, int value)
{
char buffer [BUF_TINY];
1998-02-27 07:54:42 +03:00
g_snprintf (buffer, sizeof (buffer), "%d", value);
1998-02-27 07:54:42 +03:00
return WritePrivateProfileString (app_text, key, buffer, file);
}
int exist_file (char *name)
{
return access (name, R_OK) == 0;
}
char *load_file (char *filename)
{
FILE *data_file;
struct stat s;
char *data;
long read_size;
if ((data_file = fopen (filename, "r")) == NULL){
1998-02-27 07:54:42 +03:00
return 0;
}
if (fstat (fileno (data_file), &s) != 0){
fclose (data_file);
1998-02-27 07:54:42 +03:00
return 0;
}
data = (char *) g_malloc (s.st_size+1);
1998-02-27 07:54:42 +03:00
read_size = fread (data, 1, s.st_size, data_file);
data [read_size] = 0;
fclose (data_file);
if (read_size > 0)
return data;
else {
g_free (data);
1998-02-27 07:54:42 +03:00
return 0;
}
}
char *load_mc_home_file (const char *filename, char ** allocated_filename)
{
char *hintfile_base, *hintfile;
char *lang;
char *data;
hintfile_base = concat_dir_and_file (mc_home, filename);
lang = guess_message_value (0);
hintfile = g_strdup_printf ("%s.%s", hintfile_base, lang);
data = load_file (hintfile);
if (!data) {
g_free (hintfile);
hintfile = g_strdup_printf ("%s.%.2s", hintfile_base, lang);
data = load_file (hintfile);
if (!data) {
g_free (hintfile);
hintfile = hintfile_base;
data = load_file (hintfile_base);
}
}
g_free (lang);
if (hintfile != hintfile_base)
g_free (hintfile_base);
if (allocated_filename)
*allocated_filename = hintfile;
else
g_free (hintfile);
return data;
}
1999-04-30 16:41:41 +04:00
/* Check strftime() results. Some systems (i.e. Solaris) have different
short-month-name sizes for different locales */
size_t i18n_checktimelength (void)
{
size_t length, a, b;
char buf [MAX_I18NTIMELENGTH + 1];
time_t testtime = time (NULL);
a = strftime (buf, sizeof(buf)-1, _("%b %e %H:%M"), localtime(&testtime));
b = strftime (buf, sizeof(buf)-1, _("%b %e %Y"), localtime(&testtime));
length = max (a, b);
/* Don't handle big differences. Use standard value (email bug, please) */
if ( length > MAX_I18NTIMELENGTH || length < MIN_I18NTIMELENGTH )
length = STD_I18NTIMELENGTH;
return length;
}
1998-02-27 07:54:42 +03:00
char *file_date (time_t when)
{
1999-04-30 16:41:41 +04:00
static char timebuf [MAX_I18NTIMELENGTH + 1];
1998-02-27 07:54:42 +03:00
time_t current_time = time ((time_t) 0);
1999-04-30 16:41:41 +04:00
static size_t i18n_timelength = 0;
static char *fmtyear, *fmttime;
char *fmt;
1999-04-30 16:41:41 +04:00
if (i18n_timelength == 0){
i18n_timelength = i18n_checktimelength() + 1;
/* strftime() format string for old dates */
fmtyear = _("%b %e %Y");
/* strftime() format string for recent dates */
fmttime = _("%b %e %H:%M");
}
1998-02-27 07:54:42 +03:00
if (current_time > when + 6L * 30L * 24L * 60L * 60L /* Old. */
|| current_time < when - 60L * 60L) /* In the future. */
/* The file is fairly old or in the future.
POSIX says the cutoff is 6 months old;
approximate this by 6*30 days.
Allow a 1 hour slop factor for what is considered "the future",
to allow for NFS server/client clock disagreement.
Show the year instead of the time of day. */
1999-04-30 16:41:41 +04:00
fmt = fmtyear;
else
1999-04-30 16:41:41 +04:00
fmt = fmttime;
1999-04-30 16:41:41 +04:00
strftime (timebuf, i18n_timelength, fmt, localtime(&when));
return timebuf;
1998-02-27 07:54:42 +03:00
}
/* Like file_date, but packs the data to fit in 10 columns */
char *file_date_pck (time_t when)
{
/* FIXME: Should return only 10 chars, not 14 */
return file_date (when);
}
char *extract_line (char *s, char *top)
{
static char tmp_line [BUF_MEDIUM];
1998-02-27 07:54:42 +03:00
char *t = tmp_line;
while (*s && *s != '\n' && (t - tmp_line) < sizeof (tmp_line)-1 && s < top)
*t++ = *s++;
*t = 0;
return tmp_line;
}
/* FIXME: I should write a faster version of this (Aho-Corasick stuff) */
char * _icase_search (char *text, char *data, int *lng)
{
char *d = text;
char *e = data;
int dlng = 0;
if (lng)
*lng = 0;
for (;*e; e++) {
while (*(e+1) == '\b' && *(e+2)) {
e += 2;
dlng += 2;
}
if (toupper((unsigned char) *d) == toupper((unsigned char) *e))
d++;
else {
e -= d - text;
d = text;
dlng = 0;
}
if (!*d) {
if (lng)
*lng = strlen (text) + dlng;
return e+1;
}
}
return 0;
}
/* The basename routine */
char *x_basename (char *s)
{
char *where;
return ((where = strrchr (s, PATH_SEP))) ? where + 1 : s;
1998-02-27 07:54:42 +03:00
}
void my_putenv (char *name, char *data)
{
char *full;
full = malloc (strlen (name) + strlen (data) + 2);
strcpy (full, name);
strcat (full, "=");
strcat (full, data);
1998-02-27 07:54:42 +03:00
putenv (full);
1998-02-27 07:54:42 +03:00
/* WARNING: NEVER FREE THE full VARIABLE!!!!!!!!!!!!!!!!!!!!!!!! */
/* It is used by putenv. Freeing it will corrupt the environment */
}
#endif /* !VFS_STANDALONE */
1998-02-27 07:54:42 +03:00
char *unix_error_string (int error_num)
{
static char buffer [BUF_LARGE];
1998-02-27 07:54:42 +03:00
g_snprintf (buffer, sizeof (buffer), "%s (%d)",
g_strerror (error_num), error_num);
1998-02-27 07:54:42 +03:00
return buffer;
}
#ifndef VFS_STANDALONE
1998-02-27 07:54:42 +03:00
long blocks2kilos (int blocks, int bsize)
{
if (bsize > 1024){
return blocks * (bsize / 1024);
} else if (bsize < 1024){
return blocks / (1024 /bsize);
} else
return blocks;
}
char *skip_separators (char *s)
{
for (;*s; s++)
if (*s != ' ' && *s != '\t' && *s != ',')
break;
return s;
}
char *skip_numbers (char *s)
{
for (;*s; s++)
if (!isdigit (*s))
break;
return s;
}
/* Remove all control sequences from the argument string. We define
* "control sequence", in a sort of pidgin BNF, as follows:
*
* control-seq = Esc non-'['
* | Esc '[' (0 or more digits or ';' or '?') (any other char)
*
* 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)
*/
char *strip_ctrl_codes (char *s)
{
int i; /* Current length of the string's correct (stripped) prefix */
int j; /* Number of control characters we have skipped so far */
if (!s)
return 0;
for (i = 0, j = 0; s [i+j]; ++i)
if (s [i+j] != ESC_CHAR){
if (j)
s [i] = s [i+j];
} else {
++j;
if (s [i+j++] == '[')
while (strchr ("0123456789;?", s [i+j++]))
/* Skip the control sequence's arguments */ ;
--i;
}
s[i] = 0;
return s;
}
#endif /* !VFS_STANDALONE */
1998-02-27 07:54:42 +03:00
#ifndef USE_VFS
char *get_current_wd (char *buffer, int size)
{
char *p;
int len;
p = g_get_current_dir ();
len = strlen(p) + 1;
if (len > size) {
g_free (p);
return NULL;
}
strncpy (buffer, p, len);
g_free (p);
return buffer;
}
#endif /* !USE_VFS */
1998-02-27 07:54:42 +03:00
#define CHECK(x) if (x == -1) return 0;
1998-12-03 00:27:27 +03:00
static long
get_small_endian_long (int fd)
1998-02-27 07:54:42 +03:00
{
unsigned char buffer [4];
1998-02-27 07:54:42 +03:00
CHECK (mc_read (fd, buffer, 4));
return (buffer [3] << 24) | (buffer [2] << 16) | (buffer [1] << 8) | buffer [0];
1998-02-27 07:54:42 +03:00
}
/*
* This constant makes the magic array on the stack be larger than
* it needs because Linux when reading the second byte of /proc/locks
* for example will write 2 bytes, even if we only asked for one
*/
#define LINUX_HAS_PROBLEMS_WHEN_READING_PROC_LOCKS_ON_SOME_KERNELS 40
1998-02-27 07:54:42 +03:00
/* This function returns 0 if the file is not in gunzip format */
/* or how much memory must be allocated to load the gziped file */
/* Warning: this function moves the current file pointer */
long int is_gunzipable (int fd, int *type)
{
unsigned char magic [4+LINUX_HAS_PROBLEMS_WHEN_READING_PROC_LOCKS_ON_SOME_KERNELS];
1998-02-27 07:54:42 +03:00
*type = ISGUNZIPABLE_GUNZIP;
/* Read the magic signature */
CHECK (mc_read (fd, &magic [0], 4));
1998-02-27 07:54:42 +03:00
/* GZIP_MAGIC and OLD_GZIP_MAGIC */
if (magic [0] == 037 && (magic [1] == 0213 || magic [1] == 0236)){
/* Read the uncompressed size of the file */
mc_lseek (fd, -4, SEEK_END);
return get_small_endian_long (fd);
}
/* PKZIP_MAGIC */
if (magic [0] == 0120 && magic [1] == 0113 && magic [2] == 003 && magic [3] == 004){
/* Read compression type */
mc_lseek (fd, 8, SEEK_SET);
CHECK (mc_read (fd, &magic [0], 2));
1998-02-27 07:54:42 +03:00
/* Gzip can handle only deflated (8) or stored (0) files */
if ((magic [0] != 8 && magic [0] != 0) || magic [1] != 0)
return 0;
/* Read the uncompressed size of the first file in the archive */
mc_lseek (fd, 22, SEEK_SET);
return get_small_endian_long (fd);
}
/* PACK_MAGIC and LZH_MAGIC and compress magic */
if (magic [0] == 037 && (magic [1] == 036 || magic [1] == 0240 || magic [1] == 0235)){
/* In case the file is packed, sco lzhed or compress_magic, the */
/* program guesses that the uncompressed size is (at most) four */
/* times the length of the compressed size, if the compression */
/* ratio is more than 4:1 the end of the file is not displayed */
return 4*mc_lseek (fd, 0, SEEK_END);
}
/* BZIP and BZIP2 files */
if ((magic[0] == 'B') && (magic[1] == 'Z') &&
(magic [3] >= '1') && (magic [3] <= '9')){
switch (magic[2]) {
case '0':
*type = ISGUNZIPABLE_BZIP;
return 5*mc_lseek (fd, 0, SEEK_END);
case 'h':
*type = ISGUNZIPABLE_BZIP2;
return 5*mc_lseek (fd, 0, SEEK_END);
}
}
return 0;
}
char *
decompress_extension (int type)
{
switch (type){
case ISGUNZIPABLE_GUNZIP: return "#ugz";
case ISGUNZIPABLE_BZIP: return "#ubz";
case ISGUNZIPABLE_BZIP2: return "#ubz2";
}
/* Should never reach this place */
fprintf (stderr, "Fatal: decompress_extension called with an unknown argument\n");
return 0;
}
1998-02-27 07:54:42 +03:00
char *
decompress_command (int type)
{
switch (type){
case ISGUNZIPABLE_GUNZIP:
return "gzip -cdf";
case ISGUNZIPABLE_BZIP:
return "bzip -d";
case ISGUNZIPABLE_BZIP2:
return "bzip2 -d";
}
/* Should never reach this place */
fprintf (stderr, "Fatal: decompress_command called with an unknown argument\n");
return 0;
}
void
decompress_command_and_arg (int type, char **cmd, char **flags)
{
switch (type){
case ISGUNZIPABLE_GUNZIP:
*cmd = "gzip";
*flags = "-cdf";
return;
case ISGUNZIPABLE_BZIP:
*cmd = "bzip";
*flags = "-d";
return;
case ISGUNZIPABLE_BZIP2:
*cmd = "bzip2";
*flags = "-d";
return;
}
*cmd = 0;
*flags = 0;
/* Should never reach this place */
fprintf (stderr, "Fatal: decompress_command called with an unknown argument\n");
}
#ifndef VFS_STANDALONE
1998-02-27 07:54:42 +03:00
/* Hooks */
void add_hook (Hook **hook_list, void (*hook_fn)(void *), void *data)
{
Hook *new_hook = g_new (Hook, 1);
1998-02-27 07:54:42 +03:00
new_hook->hook_fn = hook_fn;
new_hook->next = *hook_list;
new_hook->hook_data = data;
*hook_list = new_hook;
}
void execute_hooks (Hook *hook_list)
{
Hook *new_hook = 0;
Hook *p;
/* We copy the hook list first so tahat we let the hook
* function call delete_hook
*/
while (hook_list){
add_hook (&new_hook, hook_list->hook_fn, hook_list->hook_data);
hook_list = hook_list->next;
}
p = new_hook;
while (new_hook){
(*new_hook->hook_fn)(new_hook->hook_data);
new_hook = new_hook->next;
}
for (hook_list = p; hook_list;){
p = hook_list;
hook_list = hook_list->next;
g_free (p);
1998-02-27 07:54:42 +03:00
}
}
void delete_hook (Hook **hook_list, void (*hook_fn)(void *))
{
Hook *current, *new_list, *next;
new_list = 0;
for (current = *hook_list; current; current = next){
next = current->next;
if (current->hook_fn == hook_fn)
g_free (current);
1998-02-27 07:54:42 +03:00
else
add_hook (&new_list, current->hook_fn, current->hook_data);
}
*hook_list = new_list;
}
int hook_present (Hook *hook_list, void (*hook_fn)(void *))
{
Hook *p;
for (p = hook_list; p; p = p->next)
if (p->hook_fn == hook_fn)
return 1;
return 0;
}
void wipe_password (char *passwd)
{
char *p = passwd;
This commit mainly adds a password dialog to smbfs. In the Gnome Edition this dialog doesn't look perfect but at least it doesn't break gmc. 1999-09-14 Norbert Warmuth <nwarmuth@privat.circular.de> * gnome/layout: Added the new samba password dialog. * src/widget.[ch] (input_new): added const qualifier * src/util.c (wipe_password): Check for NULL. 1999-09-14 Norbert Warmuth <nwarmuth@privat.circular.de> * vfs/smbfs.c (various places): Store filenames in memory with the unix character set and convert it back to the dos character set when filenames are passed back to the samba server. If samba is configured correctly this will fix the problems with filenames which contain national characters. (bucket_set_authinfo): Set domain, username and password which will be used to log on and authenticate against the samba server and remember this information on a host/share basis. If set use PASSWD to get the password. If already authenticated against the host and share use this information. If already authenticated against host and IPC$ use this information. If neither of the former is true ask the user how to log on. (authinfo_get_authinfo_from_user): New function. Query the user for domain, username and password to use for authentication. (authinfo_free): New function. Free memory in authentication structure. (authinfo_free_all): New function. Free the list used to remember authentication information. (authinfo_compare_host_and_share, authinfo_compare_host): New functions. Helper functions used to search the authentication list. (authinfo_add): New function. Add one authentication entry to the authlist. (authinfo_remove): New function. Remove one entry from the authlist. (free_bucket): Free memory associated with one bucket. (smbfs_get_free_bucket): Initialize the complete connection array with 0. Free the memory allocated for a bucket and initialize the bucket before reusing it. (smbfs_open_link): use new functions to get authentication information (get_stat_info, smbfs_stat): remove unused variables.
1999-09-14 22:20:02 +04:00
if (!p)
return;
1998-02-27 07:54:42 +03:00
for (;*p ; p++)
*p = 0;
g_free (passwd);
1998-02-27 07:54:42 +03:00
}
/* Convert "\E" -> esc character and ^x to control-x key and ^^ to ^ key */
/* Returns a newly allocated string */
char *convert_controls (char *s)
{
char *valcopy = g_strdup (s);
1998-02-27 07:54:42 +03:00
char *p, *q;
/* Parse the escape special character */
for (p = s, q = valcopy; *p;){
if (*p == '\\'){
p++;
if ((*p == 'e') || (*p == 'E')){
p++;
*q++ = ESC_CHAR;
}
} else {
if (*p == '^'){
p++;
if (*p == '^')
*q++ = *p++;
else {
*p = (*p | 0x20);
if (*p >= 'a' && *p <= 'z') {
*q++ = *p++ - 'a' + 1;
} else
p++;
}
} else
*q++ = *p++;
}
}
*q++ = 0;
return valcopy;
}
/* Reverse the string */
char *reverse_string (char *string)
{
int len = strlen (string);
int i;
const int steps = len/2;
for (i = 0; i < steps; i++){
char c = string [i];
string [i] = string [len-i-1];
string [len-i-1] = c;
}
return string;
}
char *resolve_symlinks (char *path)
{
char *buf, *buf2, *p, *q, *r, c;
int len;
struct stat mybuf;
if (*path != PATH_SEP)
return NULL;
r = buf = g_malloc (MC_MAXPATHLEN);
buf2 = g_malloc (MC_MAXPATHLEN);
1998-02-27 07:54:42 +03:00
*r++ = PATH_SEP;
*r = 0;
p = path;
for (;;) {
q = strchr (p + 1, PATH_SEP);
if (!q) {
q = strchr (p + 1, 0);
if (q == p + 1)
break;
}
c = *q;
*q = 0;
if (mc_lstat (path, &mybuf) < 0) {
g_free (buf);
g_free (buf2);
1998-02-27 07:54:42 +03:00
*q = c;
return NULL;
}
if (!S_ISLNK (mybuf.st_mode))
strcpy (r, p + 1);
else {
len = mc_readlink (path, buf2, MC_MAXPATHLEN);
if (len < 0) {
g_free (buf);
g_free (buf2);
1998-02-27 07:54:42 +03:00
*q = c;
return NULL;
}
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;
g_free (buf2);
1998-02-27 07:54:42 +03:00
return buf;
}
/* 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 */
char *diff_two_paths (char *first, char *second)
{
char *p, *q, *r, *s, *buf = 0;
int i, j, prevlen = -1, currlen;
first = resolve_symlinks (first);
if (first == NULL)
return NULL;
for (j = 0; j < 2; j++) {
p = first;
if (j) {
second = resolve_symlinks (second);
if (second == NULL) {
g_free (first);
1998-02-27 07:54:42 +03:00
return buf;
}
}
q = 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);
1998-02-27 07:54:42 +03:00
else {
g_free (first);
g_free (second);
1998-02-27 07:54:42 +03:00
return buf;
}
}
p = buf = g_malloc (currlen);
1998-02-27 07:54:42 +03:00
prevlen = currlen;
for (; i >= 0; i--, p += 3)
strcpy (p, "../");
strcpy (p, q);
}
g_free (first);
g_free (second);
1998-02-27 07:54:42 +03:00
return buf;
}
#ifndef HAVE_TRUNCATE
/* On SCO and Windows NT systems */
int my_ftruncate (int fd, long size)
{
#ifdef OS2_NT
if(_chsize(fd, size))
return -1;
else
return 0;
#else
struct flock lk;
lk.l_whence = 0;
lk.l_start = size;
lk.l_len = 0;
return fcntl (fd, F_FREESP, &lk);
#endif /* !OS2_NT */
1998-02-27 07:54:42 +03:00
}
int truncate (const char *path, long size)
{
int fd;
int res;
fd = open (path, O_RDWR, 0);
if (fd < 0)
return fd;
res = my_ftruncate (fd, size);
if (res < 0)
return res;
close (fd);
return 0;
}
#endif /* !HAVE_TRUNCATE */
#endif /* !VFS_STANDALONE */
1998-02-27 07:54:42 +03:00
/* If filename is NULL, then we just append PATH_SEP to the dir */
1998-02-27 07:54:42 +03:00
char *
concat_dir_and_file (const char *dir, const char *file)
{
int i = strlen (dir);
if (dir [i-1] == PATH_SEP)
return g_strconcat (dir, file, NULL);
1998-02-27 07:54:42 +03:00
else
return g_strconcat (dir, PATH_SEP_STR, file, NULL);
}
/* Following code heavily borrows from libiberty, mkstemps.c */
/* Number of attempts to create a temporary file */
#ifndef TMP_MAX
#define TMP_MAX 16384
#endif /* !TMP_MAX */
/*
* Arguments:
* pname (output) - pointer to the name of the temp file (needs g_free).
* NULL if the function fails.
* prefix - part of the filename before the random part.
* Prepend $TMPDIR or /tmp if there are no path separators.
* suffix - if not NULL, part of the filename after the random part.
*
* Result:
* handle of the open file or -1 if couldn't open any.
*/
int mc_mkstemps(char **pname, const char *prefix, const char *suffix)
{
static const char letters[]
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static unsigned long value;
struct timeval tv;
char *tmpbase;
char *tmpname;
char *XXXXXX;
int count;
if (strchr(prefix, PATH_SEP) == NULL) {
char *tmpdir;
tmpdir = getenv("TMPDIR");
if (!tmpdir) {
tmpdir = TMPDIR_DEFAULT;
}
/* Add prefix first to find the position of XXXXXX */
tmpbase = concat_dir_and_file (tmpdir, prefix);
} else {
tmpbase = g_strdup (prefix);
}
tmpname = g_strconcat (tmpbase, "XXXXXX", suffix, NULL);
*pname = tmpname;
XXXXXX = &tmpname[strlen (tmpbase)];
g_free(tmpbase);
/* Get some more or less random data. */
gettimeofday (&tv, NULL);
value += (tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
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_EXCL, 0600);
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;
}
/* Unsuccessful. Free the filename. */
g_free (tmpname);
tmpname = NULL;
return -1;
}