diff options
Diffstat (limited to 'Build/source/libs/libgnuw32/filename.c')
-rw-r--r-- | Build/source/libs/libgnuw32/filename.c | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/Build/source/libs/libgnuw32/filename.c b/Build/source/libs/libgnuw32/filename.c new file mode 100644 index 00000000000..5aede5152f3 --- /dev/null +++ b/Build/source/libs/libgnuw32/filename.c @@ -0,0 +1,392 @@ +/* Utility and Unix shadow routines for XEmacs on Windows NT. + Copyright (C) 1994, 1995 Free Software Foundation, Inc. + +This file is part of XEmacs. + +XEmacs 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, or (at your option) any +later version. + +XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + + + Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */ + +/* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */ +/* Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */ +/* Adapted to fpTeX 0.4 by Fabrice Popineau <Fabrice.Popineau@supelec.fr> */ + +#include <win32lib.h> + +/* Normalize filename by converting all path separators to + the specified separator. Also conditionally convert upper + case path name components to lower case. + Returns the index of the first meaningful char in the path + past any drive specifier of unc name specifier. + Remove any multiple path separators after a leading + drive specifier or double path separator. +*/ + +int +normalize_filename (char *fp, char path_sep) +{ + char *p; + int ret, i; + + if (fp == NULL || *fp == '\0') + return 0; + + /* Always lower-case drive letters a-z, even if the filesystem + preserves case in filenames. + This is so filenames can be compared by string comparison + functions that are case-sensitive. Even case-preserving filesystems + do not distinguish case in drive letters. */ + if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z') { + *fp += 'a' - 'A'; + } + + /* Remove unneeded double slashes */ + ret = (IS_UNC_NAME(fp) ? 2 : + NAME_BEGINS_WITH_DEVICE(fp) ? + (IS_DIR_SEP(*(fp+2)) ? 3 : 2) : IS_DIR_SEP(*fp) ? 1 : 0); + for (i = ret, p = fp+i; + IS_DIR_SEP(*p); + i++, p++); + if (i > ret) { + int len = strlen(fp+i); + /* remove unneeded slashes, for the sake of win95 */ +#if 0 + fprintf(stderr, "moving %s to %s\n", fp+ret, fp+i); +#endif + memcpy(fp+ret, fp+i, len); + *(char *)(fp+ret+len) = '\0'; + } + + /* conditionnally rewrite to same path_sep, slash preferably */ + if (path_sep) { + for (p = fp; *p; p++) + if (IS_DIR_SEP(*p)) + *p = path_sep; + } + +#if 0 + fprintf(stderr, "normalize_filename returned (%d) %s\n", ret, fp); +#endif + + return ret; +} + + +/* Destructively turn backslashes into slashes. */ +void +dostounix_filename (char *p) +{ + normalize_filename (p, '/'); +} + +/* Destructively turn slashes into backslashes. */ +void +unixtodos_filename (char *p) +{ + normalize_filename (p, '\\'); +} + +/* Quote file name. */ +char * +quote_filename(char *name) +{ + int len = strlen(name); + char *quoted_name; + if (strchr(name, ' ') && *name != '"') { + quoted_name = xmalloc(len+3); + memcpy(quoted_name+1, name, len); + *quoted_name = '"'; + *(quoted_name+len+1) = '"'; + *(quoted_name+len+2) = '\0'; + } + else { + quoted_name = xstrdup(name); + } + return quoted_name; +} + +/* Unquote file name */ +char * +unquote_filename(char *name) +{ + int len = strlen(name); + if (*name == '"' && *(name + len - 1) == '"') { + memmove(name, name+1, len-2); + *(name + len - 2) = '\0'; + } + return name; +} + + +/* Remove all CR's that are followed by a LF. + (From msdos.c...probably should figure out a way to share it, + although this code isn't going to ever change.) */ +int +crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count) +{ + unsigned char *np = buf; + unsigned char *startp = buf; + unsigned char *endp = buf + n; + + if (n == 0) + return n; + while (buf < endp - 1) + { + if (*buf == 0x0a) + (*lf_count)++; + if (*buf == 0x0d) + { + if (*(++buf) != 0x0a) + *np++ = 0x0d; + } + else + *np++ = *buf++; + } + if (buf < endp) + { + if (*buf == 0x0a) + (*lf_count)++; + *np++ = *buf++; + } + return np - startp; +} + +/* Parse the root part of file name, if present. Return length and + optionally store pointer to char after root. */ +int +_parse_root (char * name, char ** pPath) +{ + char * start = name; + + if (name == NULL) + return 0; + + /* find the root name of the volume if given */ + if (isalpha (name[0]) && name[1] == ':') + { + /* skip past drive specifier */ + name += 2; + if (IS_DIR_SEP (name[0])) + name++; + } + else if (IS_DIR_SEP (name[0]) && IS_DIR_SEP (name[1])) + { + int slashes = 2; + name += 2; + do + { + if (IS_DIR_SEP (*name) && --slashes == 0) + break; + name++; + } + while ( *name ); + if (IS_DIR_SEP (name[0])) + name++; + } + + if (pPath) + *pPath = name; + + return name - start; +} + +/* Get long base name for name; name is assumed to be absolute. */ +static int +get_long_basename (char * name, char * buf, int size) +{ + WIN32_FIND_DATA find_data; + HANDLE dir_handle; + int len = 0; +#ifdef PIGSFLY + char *p; + + /* If the last component of NAME has a wildcard character, + return it as the basename. */ + p = name + strlen (name); + while (*p != '\\' && *p != ':' && p > name) p--; + if (p > name) p++; + if (strchr (p, '*') || strchr (p, '?')) + { + if ((len = strlen (p)) < size) + memcpy (buf, p, len + 1); + else + len = 0; + return len; + } +#endif + + dir_handle = FindFirstFile (name, &find_data); + if (dir_handle != INVALID_HANDLE_VALUE) + { + if ((len = strlen (find_data.cFileName)) < size) + memcpy (buf, find_data.cFileName, len + 1); + else + len = 0; + FindClose (dir_handle); + } + return len; +} + +/* Get long name for file, if possible (assumed to be absolute). */ +BOOL +win32_get_long_filename (char * name, char * buf, int size) +{ + char * o = buf; + char * p; + char * q; + char full[ MAX_PATH ]; + int len; + + len = strlen (name); + if (len >= MAX_PATH) + return FALSE; + + /* Use local copy for destructive modification. */ + memcpy (full, name, len+1); + unixtodos_filename (full); + + /* Copy root part verbatim. */ + len = _parse_root (full, &p); + memcpy (o, full, len); + o += len; + size -= len; + + do + { + q = p; + p = strchr (q, '\\'); + if (p) *p = '\0'; + len = get_long_basename (full, o, size); + if (len > 0) + { + o += len; + size -= len; + if (p != NULL) + { + *p++ = '\\'; + if (size < 2) + return FALSE; + *o++ = '\\'; + size--; + *o = '\0'; + } + } + else + return FALSE; + } + while (p != NULL && *p); + + return TRUE; +} + +/* Map filename to a legal 8.3 name if necessary. */ +const char * +map_win32_filename (const char * name, const char ** pPath) +{ + static char shortname[MAX_PATH]; + char * str = shortname; + char c; + const char * path; + const char * save_name = name; + + if (is_fat_volume (name, &path)) /* truncate to 8.3 */ + { + register int left = 8; /* maximum number of chars in part */ + register int extn = 0; /* extension added? */ + register int dots = 2; /* maximum number of dots allowed */ + + while (name < path) + *str++ = *name++; /* skip past UNC header */ + + while ((c = *name++)) + { + switch ( c ) + { + case '\\': + case '/': + *str++ = '\\'; + extn = 0; /* reset extension flags */ + dots = 2; /* max 2 dots */ + left = 8; /* max length 8 for main part */ + break; + case ':': + *str++ = ':'; + extn = 0; /* reset extension flags */ + dots = 2; /* max 2 dots */ + left = 8; /* max length 8 for main part */ + break; + case '.': + if ( dots ) + { + /* Convert path components of the form .xxx to _xxx, + but leave . and .. as they are. This allows .emacs + to be read as _emacs, for example. */ + + if (! *name || + *name == '.' || + IS_DIR_SEP (*name)) + { + *str++ = '.'; + dots--; + } + else + { + *str++ = '_'; + left--; + dots = 0; + } + } + else if ( !extn ) + { + *str++ = '.'; + extn = 1; /* we've got an extension */ + left = 3; /* 3 chars in extension */ + } + else + { + /* any embedded dots after the first are converted to _ */ + *str++ = '_'; + } + break; + case '~': + case '#': /* don't lose these, they're important */ + if ( ! left ) + str[-1] = c; /* replace last character of part */ + /* FALLTHRU */ + default: + if ( left ) + { + *str++ = tolower (c); /* map to lower case (looks nicer) */ + left--; + dots = 0; /* started a path component */ + } + break; + } + } + *str = '\0'; + } + else + { + strcpy (shortname, name); + unixtodos_filename (shortname); + } + + if (pPath) + *pPath = shortname + (path - save_name); + + return shortname; +} |