From: <bi...@us...> - 2008-07-05 13:04:32
|
Revision: 2660 http://oorexx.svn.sourceforge.net/oorexx/?rev=2660&view=rev Author: bigrixx Date: 2008-07-05 06:04:39 -0700 (Sat, 05 Jul 2008) Log Message: ----------- reorganize file system methods Modified Paths: -------------- interpreter-3.x/trunk/kernel/parser/SourceFile.cpp interpreter-3.x/trunk/kernel/platform/unix/FileSystem.cpp interpreter-3.x/trunk/kernel/platform/unix/SysFileSystem.cpp interpreter-3.x/trunk/kernel/platform/unix/SysFileSystem.hpp interpreter-3.x/trunk/kernel/platform/unix/SysInterpreterInstance.hpp interpreter-3.x/trunk/kernel/platform/unix/SystemInterpreter.hpp interpreter-3.x/trunk/kernel/platform/windows/FileSystem.cpp interpreter-3.x/trunk/kernel/platform/windows/SysFileSystem.cpp interpreter-3.x/trunk/kernel/platform/windows/SysFileSystem.hpp interpreter-3.x/trunk/kernel/platform/windows/SysInterpreterInstance.hpp interpreter-3.x/trunk/kernel/platform/windows/SystemInterpreter.hpp Modified: interpreter-3.x/trunk/kernel/parser/SourceFile.cpp =================================================================== --- interpreter-3.x/trunk/kernel/parser/SourceFile.cpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/parser/SourceFile.cpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -84,6 +84,7 @@ #include "LibraryDirective.hpp" #include "RequiresDirective.hpp" #include "PackageManager.hpp" +#include "SysFileSystem.hpp" #define HOLDSIZE 60 /* room for 60 temporaries */ @@ -320,9 +321,9 @@ return; } - OrefSet(this, this->programDirectory, SystemInterpreter::extractDirectory(programName)); - OrefSet(this, this->programExtension, SystemInterpreter::extractExtension(programName)); - OrefSet(this, this->programFile, SystemInterpreter::extractFile(programName)); + OrefSet(this, this->programDirectory, SysFileSystem::extractDirectory(programName)); + OrefSet(this, this->programExtension, SysFileSystem::extractExtension(programName)); + OrefSet(this, this->programFile, SysFileSystem::extractFile(programName)); } Modified: interpreter-3.x/trunk/kernel/platform/unix/FileSystem.cpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/unix/FileSystem.cpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/unix/FileSystem.cpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -51,6 +51,7 @@ #include "ProtectedObject.hpp" #include "SystemInterpreter.hpp" #include "SysInterpreterInstance.hpp" +#include "SysFileSystem.hpp" #include <string.h> #include <stdio.h> #include <stddef.h> @@ -73,73 +74,6 @@ /** - * Extract directory information from a file name. - * - * @param file The input file name. If this represents a real source file, - * this will be fully resolved. - * - * @return The directory portion of the file name. If the file name - * does not include a directory portion, then OREF_NULL is returned. - */ -RexxString *SystemInterpreter::extractDirectory(RexxString *file) -{ - const char *pathName = file->getStringData(); - const char *endPtr = pathName + file->getLength() - 1; - - // scan backwards looking for a directory delimiter. This name should - // be fully qualified, so we don't have to deal with drive letters - while (pathName < endPtr) - { - // find the first directory element? - if (*endPtr == '/') - { - // extract the directory information, including the final delimiter - // and return as a string object. - return new_string(pathName, endPtr - pathName + 1); - } - endPtr--; - } - return OREF_NULL; // not available -} - - -/** - * Extract extension information from a file name. - * - * @param file The input file name. If this represents a real source file, - * this will be fully resolved. - * - * @return The extension portion of the file name. If the file - * name does not include an extension portion, then - * OREF_NULL is returned. - */ -RexxString *SystemInterpreter::extractExtension(RexxString *file) -{ - const char *pathName = file->getStringData(); - const char *endPtr = pathName + file->getLength() - 1; - - // scan backwards looking for a directory delimiter. This name should - // be fully qualified, so we don't have to deal with drive letters - while (pathName < endPtr) - { - // find the first directory element? - if (*endPtr == '/') - { - return OREF_NULL; // found a directory portion before an extension...we're extensionless - } - // is this the extension dot? - else if (*endPtr == '.') - { - // return everything from the period on. Keeping the period on is a convenience. - return new_string(endPtr); - } - endPtr--; - } - return OREF_NULL; // not available -} - - -/** * Resolve a program for intial loading or a subroutine call. * * @param _name The target name. This can be fully qualified, or a simple name @@ -167,9 +101,9 @@ // if the file already has an extension, this dramatically reduces the number // of searches we need to make. - if (hasExtension(name)) + if (SysFileSystem::hasExtension(name)) { - if (searchName(name, searchPath.path, NULL, resolvedName)) + if (SysFileSystem::searchName(name, searchPath.path, NULL, resolvedName)) { return new_string(resolvedName); } @@ -179,7 +113,7 @@ // if we have a parent extension provided, use that in preference to any default searches if (parentExtension != NULL) { - if (searchName(name, searchPath.path, parentExtension, resolvedName)) + if (SysFileSystem::searchName(name, searchPath.path, parentExtension, resolvedName)) { return new_string(resolvedName); } @@ -192,14 +126,14 @@ { RexxString *ext = (RexxString *)searchExtensions->get(i); - if (searchName(name, searchPath.path, ext->getStringData(), resolvedName)) + if (SysFileSystem::searchName(name, searchPath.path, ext->getStringData(), resolvedName)) { return new_string(resolvedName); } } // The file may purposefully have no extension. - if (searchName(name, searchPath.path, NULL, resolvedName)) + if (SysFileSystem::searchName(name, searchPath.path, NULL, resolvedName)) { return new_string(resolvedName); } @@ -208,319 +142,22 @@ } -/** - * Test if a filename has an extension. - * - * @param name The name to check. - * - * @return true if an extension was found on the file, false if there - * is no extension. - */ -bool SysInterpreterInstance::hasExtension(const char *name) -{ - const char *endPtr = name + strlen(name) - 1 - - // scan backwards looking for a directory delimiter. This name should - // be fully qualified, so we don't have to deal with drive letters - while (name < endPtr) - { - // find the first directory element? - if (*endPtr == '\\') - { - return false; // found a directory portion before an extension...we're extensionless - } - // is this the extension dot? - else if (*endPtr == '.') - { - // return everything from the period on. Keeping the period on is a convenience. - return true; - } - endPtr--; - } - return false; // not available -} - - -/** - * Do a search for a single variation of a filename. - * - * @param name The name to search for. - * @param directory A specific directory to look in first (can be NULL). - * @param extension A potential extension to add to the file name (can be NULL). - * @param resolvedName - * The buffer used to return the resolved file name. - * - * @return true if the file was located. A true returns indicates the - * resolved file name has been placed in the provided buffer. - */ -bool SysInterpreterInstance::searchName(const char *name, const char *path, const char *extension, char *resolvedName) -{ - UnsafeBlock releaser; - // this is for building a temporary name - char tempName[CCHMAXPATH + 2]; - - // construct the search name, potentially adding on an extension - strncpy(tempName, name, sizeof(tempName)); - if (extension != OREF) - { - strncat(tempName, extension, sizeof(tempName)); - } - - // for each name, check in both the provided case and lower case. - for (int i = 0; i < 2; i++) - { - // check the file as is first - if (checkCurrentFile(tempName, resolvedName)) - { - return true; - } - - // we don't do path searches if there's directory information in the name - if (!hasDirectory(tempName)) - { - // go search along the path - if (searchPath(tempName, path, resolvedName)) - { - return true; - } - } - // try again in lower case - strlower(tempName); - } - return false; -} - - -/** - * Try to locate a file using just the raw name passed in, as - * opposed to searching along a path for the name. - * - * @param name The name to use for the search. - * - * @return An RexxString version of the file name, iff the file was located. Returns - * OREF_NULL if the file did not exist. - */ -bool SysInterpreterInstance::checkCurrentFile(const char *name, char *resolvedName) -{ - // validate that this is a name that can even be located. - size_t nameLength = strlen(name); - - if (nameLength < 1 || NameLength > CCHMAXPATH) - { - return false; - } - - // make a copy of the input name - strcpy(resolvedName, name); - // take care of any special conditions in the name structure - // a failure here means an invalid name of some sort - if (!canonicalizeName(resolvedName)) - { - return false; - } - - struct stat dummy; /* structure for stat system calls */ - - // ok, if this exists, life is good. Return it. - if (stat(resolvedName, &dummy)) /* look for file */ - { - return true; - } - // not found - return false; -} - - -/** - * Do a path search for a file. - * - * @param name The name to search for. - * @param path The search path to use. - * @param resolvedName - * A buffer used for returning the resolved name. - * - * @return Returns true if the file was located. If true, the resolvedName - * buffer will contain the returned name. - */ -bool SysInterpreterInstance::searchPath(const char *name, const char *path, char *resolvedName) -{ - // get an end pointer - const char *pathEnd = path + strlen(path); - - /* For every dir in searchpath*/ - for (const char *p = path, const char *q = strchr(p, ':'); p < pathEnd; p = q + 1, q = strchr(p, ':')) - { - // it's possible we've hit the end, in which case, point the delimiter marker past the end of the - // string - if (q == NULL) - { - q = pathEnd; - } - size_t sublength = q - p; - - memcpy(resolvedName, p, sublength); - resolvedName[sublength] = '/'; - resolvedName[sublength + 1] = '\0'; - strncat(resolvedName, name, CCHMAXPATH) - - // take care of any special conditions in the name structure - // a failure here means an invalid name of some sort - if (canonicalizeName(resolvedName)) - { - if (!stat(resolvedName, &dummy)) /* If file is found, */ - { - return true; - } - } - } - return false; -} - - -/** - * Process a file name to add the current working directory - * or the home directory, as needed, then remove all of the - * . and .. elements. - * - * @param name The current working name. - * - * @return true if this was valid enough to normalize. - */ -bool SysInterpreterInstance::canonicalizeName(char *name) -{ - // copy over the reduced form - strncpy(name, tempName, CCHMAXPATH); - - // does it start with the user home marker? - if (name[0] == '~') - { - // this is the typical case. This is a directory based off of - // the current users home directory. - if (name[1] == '/') - { - - char tempName[CCHMAXPATH + 2]; - // make a copy of the name - strncpy(tempName, name, CCHMAXPATH); - strcpy(name, getenv("HOME")); - // if we need a separator, add one - if (name[1] != '/') - { - strncat(name, "/", CCHMAXPATH); - } - strncat(name, tempName + 1, CCHMAXPATH); - } - else - { - // referencing a file in some other user's home directory. - // we need to extract the username and resolve that home directory - char tempName[CCHMAXPATH + 2]; - char userName[CCHMAXPATH + 2]; - - // make a copy of the name - strncpy(tempName, name, CCHMAXPATH); - // look for the start of a directory - char *slash = strchr(tempName,'/'); - // if there is a directory after the username, we need - // to copy just the name piece - if (!slash != NULL) - { - size_t nameLength = slash - tempName - 1; - memcpy(userName, tempName + 1, nameLength; - userName[nameLength] = '\0'; - } - // all username, just copy - else - { - strcpy(userName, tempName + 1); - } - - // see if we can retrieve the information - struct passwd *ppwd getpwnam(userName); - if (ppwd == NULL) - { - // this is not valid without user information, so just fail the operation - // if we can't get this. - return false; /* nothing happend */ - } - - strncpy(name, ppwd->pw_dir, CCHMAXPATH); - // if we have a directory after the username, copy the whole thing - if (slash != NULL) - { - strncat(name, slash, CCHMAXPATH); - } - } - } - - // if we're not starting with root, we need to add the - // current working directory. This will also handle the - // "." and ".." cases, which will be removed by the canonicalization - // process. - else if (name[0] != '/') - { - char tempName[CCHMAXPATH + 2]; - // make a copy of the name - strncpy(tempName, name, CCHMAXPATH); - getcwd(name, CCHMAXPATH); - strncat(name, "/", CCHMAXPATH); - strncat(name, tempName, CCHMAXPATH); - } - - char *tempName = canonicalize_file_name(name); - if (tempName == NULL) - { - return false; - } - return true; -} - - -/** - * Portable implementation of an ascii-z string to uppercase (in place). - * - * @param str String argument - * - * @return The address of the str unput argument. - */ -void strlower(char *str) -{ - while (*str) - { - *str = tolower(*str); - str++; - } - - return; -} - - void SystemInterpreter::loadImage(char **imageBuffer, size_t *imageSize) /*******************************************************************/ /* Function : Load the image into storage */ /*******************************************************************/ { - FILE *image = NULL; - const char *fullname; - - fullname = searchFileName(BASEIMAGE, 'P'); /* PATH search */ - -#ifdef ORX_CATDIR - if ( fullname == OREF_NULL ) + char fullname[CCHMAXPATH + 2]; // finally resolved name + // The file may purposefully have no extension. + if (!SysFileSystem::searchName(BASEIMAGE, getenv("PATH"), NULL, fullname)) { - fullname = ORX_CATDIR"/rexx.img"; - } +#ifdef ORX_CATDIR + strcpy(fullname, ORX_CATDIR"/rexx.img"); +#else + logic_error("no startup image"); /* open failure */ #endif - - if ( fullname != OREF_NULL ) - { - image = fopen(fullname, "rb");/* try to open the file */ } - else - { - logic_error("no startup image"); /* open failure */ - } - + FILE *image = fopen(fullname, "rb");/* try to open the file */ if ( image == NULL ) { logic_error("unable to open image file"); @@ -586,53 +223,17 @@ /* Function: Qualify a stream name for this system */ /*******************************************************************/ { - char nameBuffer[SysFileSystem::MaximumFileNameBuffer]; + char nameBuffer[SysFileSystem::MaximumFileNameBuffer]; - /* clear out the block */ - memset(nameBuffer, 0, sizeof(nameBuffer)); - SysFileSystem::qualifyStreamName(name->getStringData(), nameBuffer, sizeof(nameBuffer)); /* expand the full name */ - /* uppercase this */ - SysUtil::strupr(nameBuffer); - /* get the qualified file name */ - return new_string(nameBuffer); + /* clear out the block */ + memset(nameBuffer, 0, sizeof(nameBuffer)); + SysFileSystem::qualifyStreamName(name->getStringData(), nameBuffer, sizeof(nameBuffer)); /* expand the full name */ + /* uppercase this */ + SysUtil::strupr(nameBuffer); + /* get the qualified file name */ + return new_string(nameBuffer); } -bool SearchFirstFile( - const char *Name) /* name of file with wildcards */ -{ - return(0); -} -#if defined( FIONREAD ) -int SysPeekSTD(STREAM_INFO *stream_info) -{ - int c; - - /* ioctl returns number of fully received bytes from keyboard, after */ - /* the Enter key has been hit. After the first byte has been read with */ - /* charin, ioctl returns '0'. stream_file->_cnt returns '0' until a first */ - /* charin has buffered input from STDIN. After that _cnt returns the num- */ - /* of still buffered characters. If new input arrives through STDIN, the */ - /* already buffered input is worked off, _cnt gets '0' and with that, */ - /* ioctl returns a non zero value. With the first charin, the logic repeats */ - - ioctl(stream_info->fh, FIONREAD, &c); -#if defined( HAVE_FILE__IO_READ_PTR ) - if ( (!c) && (!(stream_info->stream_file->_IO_read_ptr < - stream_info->stream_file->_IO_read_end)) ) -#elif defined( HAVE_FILE__CNT ) - if( (!c) && (!stream_info->stream_file->_cnt) ) -#else - if ( !c ) /* not sure what to do here ? */ -#endif - return(0); - else - return(1); -} -#endif - - - - Modified: interpreter-3.x/trunk/kernel/platform/unix/SysFileSystem.cpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/unix/SysFileSystem.cpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/unix/SysFileSystem.cpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -42,6 +42,8 @@ /* */ /******************************************************************************/ +#include "RexxCore.h" + #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -65,9 +67,6 @@ const char *SysFileSystem::EOL_Marker = "\n"; const char SysFileSystem::PathDelimiter = '/'; - - - /*********************************************************************/ /* */ /* FUNCTION : SearchFileName */ @@ -296,7 +295,389 @@ } +/** + * Extract directory information from a file name. + * + * @param file The input file name. If this represents a real source file, + * this will be fully resolved. + * + * @return The directory portion of the file name. If the file name + * does not include a directory portion, then OREF_NULL is returned. + */ +RexxString *SysFileSystem::extractDirectory(RexxString *file) +{ + const char *pathName = file->getStringData(); + const char *endPtr = pathName + file->getLength() - 1; + // scan backwards looking for a directory delimiter. This name should + // be fully qualified, so we don't have to deal with drive letters + while (pathName < endPtr) + { + // find the first directory element? + if (*endPtr == '/') + { + // extract the directory information, including the final delimiter + // and return as a string object. + return new_string(pathName, endPtr - pathName + 1); + } + endPtr--; + } + return OREF_NULL; // not available +} +/** + * Extract extension information from a file name. + * + * @param file The input file name. If this represents a real source file, + * this will be fully resolved. + * + * @return The extension portion of the file name. If the file + * name does not include an extension portion, then + * OREF_NULL is returned. + */ +RexxString *SysFileSystem::extractExtension(RexxString *file) +{ + const char *pathName = file->getStringData(); + const char *endPtr = pathName + file->getLength() - 1; + // scan backwards looking for a directory delimiter. This name should + // be fully qualified, so we don't have to deal with drive letters + while (pathName < endPtr) + { + // find the first directory element? + if (*endPtr == '/') + { + return OREF_NULL; // found a directory portion before an extension...we're extensionless + } + // is this the extension dot? + else if (*endPtr == '.') + { + // return everything from the period on. Keeping the period on is a convenience. + return new_string(endPtr); + } + endPtr--; + } + return OREF_NULL; // not available +} + + +/** + * Extract file information from a file name. + * + * @param file The input file name. If this represents a real source file, + * this will be fully resolved. + * + * @return The file portion of the file name. If the file name + * does not include a directory portion, then the entire + * string is returned + */ +RexxString *SysFileSystem::extractFile(RexxString *file) +{ + const char *pathName = file->getStringData(); + const char *endPtr = pathName + file->getLength() - 1; + + // scan backwards looking for a directory delimiter. This name should + // be fully qualified, so we don't have to deal with drive letters + while (pathName < endPtr) + { + // find the first directory element? + if (*endPtr == '/') + { + // extract the directory information, including the final delimiter + // and return as a string object. + return new_string(endPtr); + } + endPtr--; + } + return file; // this is all filename +} + + +/** + * Test if a filename has an extension. + * + * @param name The name to check. + * + * @return true if an extension was found on the file, false if there + * is no extension. + */ +bool SysFileSystem::hasExtension(const char *name) +{ + const char *endPtr = name + strlen(name) - 1 + + // scan backwards looking for a directory delimiter. This name should + // be fully qualified, so we don't have to deal with drive letters + while (name < endPtr) + { + // find the first directory element? + if (*endPtr == '\\') + { + return false; // found a directory portion before an extension...we're extensionless + } + // is this the extension dot? + else if (*endPtr == '.') + { + // return everything from the period on. Keeping the period on is a convenience. + return true; + } + endPtr--; + } + return false; // not available +} + + +/** + * Do a search for a single variation of a filename. + * + * @param name The name to search for. + * @param directory A specific directory to look in first (can be NULL). + * @param extension A potential extension to add to the file name (can be NULL). + * @param resolvedName + * The buffer used to return the resolved file name. + * + * @return true if the file was located. A true returns indicates the + * resolved file name has been placed in the provided buffer. + */ +bool SysFileSystem::searchName(const char *name, const char *path, const char *extension, char *resolvedName) +{ + UnsafeBlock releaser; + // this is for building a temporary name + char tempName[CCHMAXPATH + 2]; + + // construct the search name, potentially adding on an extension + strncpy(tempName, name, sizeof(tempName)); + if (extension != OREF) + { + strncat(tempName, extension, sizeof(tempName)); + } + + // for each name, check in both the provided case and lower case. + for (int i = 0; i < 2; i++) + { + // check the file as is first + if (checkCurrentFile(tempName, resolvedName)) + { + return true; + } + + // we don't do path searches if there's directory information in the name + if (!hasDirectory(tempName)) + { + // go search along the path + if (searchPath(tempName, path, resolvedName)) + { + return true; + } + } + // try again in lower case + strlower(tempName); + } + return false; +} + + +/** + * Try to locate a file using just the raw name passed in, as + * opposed to searching along a path for the name. + * + * @param name The name to use for the search. + * + * @return An RexxString version of the file name, iff the file was located. Returns + * OREF_NULL if the file did not exist. + */ +bool SysFileSystem::checkCurrentFile(const char *name, char *resolvedName) +{ + // validate that this is a name that can even be located. + size_t nameLength = strlen(name); + + if (nameLength < 1 || NameLength > CCHMAXPATH) + { + return false; + } + + // make a copy of the input name + strcpy(resolvedName, name); + // take care of any special conditions in the name structure + // a failure here means an invalid name of some sort + if (!canonicalizeName(resolvedName)) + { + return false; + } + + struct stat dummy; /* structure for stat system calls */ + + // ok, if this exists, life is good. Return it. + if (stat(resolvedName, &dummy)) /* look for file */ + { + return true; + } + // not found + return false; +} + + +/** + * Do a path search for a file. + * + * @param name The name to search for. + * @param path The search path to use. + * @param resolvedName + * A buffer used for returning the resolved name. + * + * @return Returns true if the file was located. If true, the resolvedName + * buffer will contain the returned name. + */ +bool SysFileSystem::searchPath(const char *name, const char *path, char *resolvedName) +{ + // get an end pointer + const char *pathEnd = path + strlen(path); + + /* For every dir in searchpath*/ + for (const char *p = path, const char *q = strchr(p, ':'); p < pathEnd; p = q + 1, q = strchr(p, ':')) + { + // it's possible we've hit the end, in which case, point the delimiter marker past the end of the + // string + if (q == NULL) + { + q = pathEnd; + } + size_t sublength = q - p; + + memcpy(resolvedName, p, sublength); + resolvedName[sublength] = '/'; + resolvedName[sublength + 1] = '\0'; + strncat(resolvedName, name, CCHMAXPATH) + + // take care of any special conditions in the name structure + // a failure here means an invalid name of some sort + if (canonicalizeName(resolvedName)) + { + if (!stat(resolvedName, &dummy)) /* If file is found, */ + { + return true; + } + } + } + return false; +} + + +/** + * Process a file name to add the current working directory + * or the home directory, as needed, then remove all of the + * . and .. elements. + * + * @param name The current working name. + * + * @return true if this was valid enough to normalize. + */ +bool SysFileSystem::canonicalizeName(char *name) +{ + // copy over the reduced form + strncpy(name, tempName, CCHMAXPATH); + + // does it start with the user home marker? + if (name[0] == '~') + { + // this is the typical case. This is a directory based off of + // the current users home directory. + if (name[1] == '/') + { + + char tempName[CCHMAXPATH + 2]; + // make a copy of the name + strncpy(tempName, name, CCHMAXPATH); + strcpy(name, getenv("HOME")); + // if we need a separator, add one + if (name[1] != '/') + { + strncat(name, "/", CCHMAXPATH); + } + strncat(name, tempName + 1, CCHMAXPATH); + } + else + { + // referencing a file in some other user's home directory. + // we need to extract the username and resolve that home directory + char tempName[CCHMAXPATH + 2]; + char userName[CCHMAXPATH + 2]; + + // make a copy of the name + strncpy(tempName, name, CCHMAXPATH); + // look for the start of a directory + char *slash = strchr(tempName,'/'); + // if there is a directory after the username, we need + // to copy just the name piece + if (!slash != NULL) + { + size_t nameLength = slash - tempName - 1; + memcpy(userName, tempName + 1, nameLength; + userName[nameLength] = '\0'; + } + // all username, just copy + else + { + strcpy(userName, tempName + 1); + } + + // see if we can retrieve the information + struct passwd *ppwd getpwnam(userName); + if (ppwd == NULL) + { + // this is not valid without user information, so just fail the operation + // if we can't get this. + return false; /* nothing happend */ + } + + strncpy(name, ppwd->pw_dir, CCHMAXPATH); + // if we have a directory after the username, copy the whole thing + if (slash != NULL) + { + strncat(name, slash, CCHMAXPATH); + } + } + } + + // if we're not starting with root, we need to add the + // current working directory. This will also handle the + // "." and ".." cases, which will be removed by the canonicalization + // process. + else if (name[0] != '/') + { + char tempName[CCHMAXPATH + 2]; + // make a copy of the name + strncpy(tempName, name, CCHMAXPATH); + getcwd(name, CCHMAXPATH); + strncat(name, "/", CCHMAXPATH); + strncat(name, tempName, CCHMAXPATH); + } + + char *tempName = canonicalize_file_name(name); + if (tempName == NULL) + { + return false; + } + return true; +} + + +/** + * Portable implementation of an ascii-z string to uppercase (in place). + * + * @param str String argument + * + * @return The address of the str unput argument. + */ +void strlower(char *str) +{ + while (*str) + { + *str = tolower(*str); + str++; + } + + return; +} + + Modified: interpreter-3.x/trunk/kernel/platform/unix/SysFileSystem.hpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/unix/SysFileSystem.hpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/unix/SysFileSystem.hpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -70,6 +70,8 @@ #define NAME_BUFFER_LENGTH (MAXIMUM_PATH_LENGTH + MAXIMUM_FILENAME_LENGTH) +class RexxString; + class SysFileSystem { public: @@ -94,6 +96,14 @@ static void qualifyStreamName(char *unqualifiedName, char *qualifiedName, size_t bufferSize); static bool findFirstFile(char *name); static bool fileExists(char *name); + static bool searchName(const char *name, const char *path, const char *extension, char *resolvedName); + static bool checkCurrentFile(const char *name, char *resolvedName); + static bool searchPath(const char *name, const char *path, const char *extension, char *resolvedName); + static bool hasExtension(const char *name); + static bool canonicalizeName(char *name); + static RexxString *extractDirectory(RexxString *file); + static RexxString *extractExtension(RexxString *file); + static RexxString *extractFile(RexxString *file); }; #endif Modified: interpreter-3.x/trunk/kernel/platform/unix/SysInterpreterInstance.hpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/unix/SysInterpreterInstance.hpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/unix/SysInterpreterInstance.hpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -43,7 +43,7 @@ #ifndef Included_SysInterpreterInstance_hpp #define Included_SysInterpreterinstance_hpp -class InterpreterInstance; +class InterpreterInstance; class SysInterpreterInstance { @@ -53,14 +53,9 @@ void initialize(InterpreterInstance *i, RexxOption *options); RexxString *resolveProgramName(RexxString *_name, RexxString *_parentDir, RexxString *_parentExtension); - static bool searchPath(const char *name, const char *path, const char *extension, char *resolvedName); - static bool searchName(const char *name, const char *path, const char *extension, char *resolvedName); - static bool checkCurrentFile(const char *name, char *resolvedName); protected: - bool hasExtension(const char *name); void addSearchExtension(const char *name); - bool canonicalizeName(char *name); InterpreterInstance *instance; // backlink to our instance container }; Modified: interpreter-3.x/trunk/kernel/platform/unix/SystemInterpreter.hpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/unix/SystemInterpreter.hpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/unix/SystemInterpreter.hpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -74,9 +74,6 @@ static void terminateInstance(InterpreterInstance *instance); static void getCurrentWorkingDirectory(char *); - static RexxString *extractDirectory(RexxString *file); - static RexxString *extractExtension(RexxString *file); - static RexxString *extractFile(RexxString *file); static RexxObject *popEnvironment(RexxActivation *context); static RexxObject *pushEnvironment(RexxActivation *context); static void restoreEnvironment(void *CurrentEnv); Modified: interpreter-3.x/trunk/kernel/platform/windows/FileSystem.cpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/windows/FileSystem.cpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/windows/FileSystem.cpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -60,108 +60,8 @@ #define WANT_GETLONGPATHNAME_WRAPPER /* NT and Windows 95 */ #include <NewAPIs.h> -bool FindFirstFile(const char *Name); /** - * Extract directory information from a file name. - * - * @param file The input file name. If this represents a real source file, - * this will be fully resolved. - * - * @return The directory portion of the file name. If the file name - * does not include a directory portion, then OREF_NULL is returned. - */ -RexxString *SystemInterpreter::extractDirectory(RexxString *file) -{ - const char *pathName = file->getStringData(); - const char *endPtr = pathName + file->getLength() - 1; - - // scan backwards looking for a directory delimiter. This name should - // be fully qualified, so we don't have to deal with drive letters - while (pathName < endPtr) - { - // find the first directory element? - if (*endPtr == '\\') - { - // extract the directory information, including the final delimiter - // and return as a string object. - return new_string(pathName, endPtr - pathName + 1); - } - endPtr--; - } - return OREF_NULL; // not available -} - - -/** - * Extract extension information from a file name. - * - * @param file The input file name. If this represents a real source file, - * this will be fully resolved. - * - * @return The extension portion of the file name. If the file - * name does not include an extension portion, then - * OREF_NULL is returned. - */ -RexxString *SystemInterpreter::extractExtension(RexxString *file) -{ - const char *pathName = file->getStringData(); - const char *endPtr = pathName + file->getLength() - 1; - - // scan backwards looking for a directory delimiter. This name should - // be fully qualified, so we don't have to deal with drive letters - while (pathName < endPtr) - { - // find the first directory element? - if (*endPtr == '\\') - { - return OREF_NULL; // found a directory portion before an extension...we're extensionless - } - // is this the extension dot? - else if (*endPtr == '.') - { - // return everything from the period on. Keeping the period on is a convenience. - return new_string(endPtr); - } - endPtr--; - } - return OREF_NULL; // not available -} - - -/** - * Extract file nformation from a file name. - * - * @param file The input file name. If this represents a real source file, - * this will be fully resolved. - * - * @return The file portion of the file name. If the file name - * does not include a directory portion, then the entire - * string is returned - */ -RexxString *SystemInterpreter::extractFile(RexxString *file) -{ - const char *pathName = file->getStringData(); - const char *endPtr = pathName + file->getLength() - 1; - - // scan backwards looking for a directory delimiter. This name should - // be fully qualified, so we don't have to deal with drive letters - while (pathName < endPtr) - { - // find the first directory element? - if (*endPtr == '\\') - { - // extract the directory information, including the final delimiter - // and return as a string object. - return new_string(endPtr); - } - endPtr--; - } - return file; // this is all filename -} - - -/** * Resolve a program for intial loading or a subroutine call. * * @param _name The target name. This can be fully qualified, or a simple name @@ -190,9 +90,9 @@ // if the file already has an extension, this dramatically reduces the number // of searches we need to make. - if (hasExtension(name)) + if (SysFileSystem::hasExtension(name)) { - if (searchName(name, searchPath.path, NULL, resolvedName)) + if (SysFileSystem::searchName(name, searchPath.path, NULL, resolvedName)) { return new_string(resolvedName); } @@ -202,7 +102,7 @@ // if we have a parent extension provided, use that in preference to any default searches if (parentExtension != NULL) { - if (searchName(name, searchPath.path, parentExtension, resolvedName)) + if (SysFileSystem::searchName(name, searchPath.path, parentExtension, resolvedName)) { return new_string(resolvedName); } @@ -214,14 +114,14 @@ { RexxString *ext = (RexxString *)instance->searchExtensions->getValue(i); - if (searchName(name, searchPath.path, ext->getStringData(), resolvedName)) + if (SysFileSystem::searchName(name, searchPath.path, ext->getStringData(), resolvedName)) { return new_string(resolvedName); } } // The file may purposefully have no extension. - if (searchName(name, searchPath.path, NULL, resolvedName)) + if (SysFileSystem::searchName(name, searchPath.path, NULL, resolvedName)) { return new_string(resolvedName); } @@ -229,188 +129,6 @@ return OREF_NULL; } - -/** - * Test if a filename has an extension. - * - * @param name The name to check. - * - * @return true if an extension was found on the file, false if there - * is no extension. - */ -bool SysInterpreterInstance::hasExtension(const char *name) -{ - const char *endPtr = name + strlen(name) - 1; - - // scan backwards looking for a directory delimiter. This name should - // be fully qualified, so we don't have to deal with drive letters - while (name < endPtr) - { - // find the first directory element? - if (*endPtr == '/') - { - return false; // found a directory portion before an extension...we're extensionless - } - // is this the extension dot? - else if (*endPtr == '.') - { - // return everything from the period on. Keeping the period on is a convenience. - return true; - } - endPtr--; - } - return false; // not available -} - - -/** - * Do a search for a single variation of a filename. - * - * @param name The name to search for. - * @param directory A specific directory to look in first (can be NULL). - * @param extension A potential extension to add to the file name (can be NULL). - * @param resolvedName - * The buffer used to return the resolved file name. - * - * @return true if the file was located. A true returns indicates the - * resolved file name has been placed in the provided buffer. - */ -bool SysInterpreterInstance::searchName(const char *name, const char *path, const char *extension, char *resolvedName) -{ - UnsafeBlock releaser; - // this is for building a temporary name - char tempName[CCHMAXPATH + 2]; - - // construct the search name, potentially adding on an extension - strncpy(tempName, name, sizeof(tempName)); - if (extension != NULL) - { - strncat(tempName, extension, sizeof(tempName)); - } - - // check the file as is first - if (checkCurrentFile(tempName, resolvedName)) - { - return true; - } - - *resolvedName = '\0'; - if (searchPath(name, path, extension, resolvedName)) - { - return true; - } - return false; -} - - - -/** - * Try to locate a file using just the raw name passed in, as - * opposed to searching along a path for the name. - * - * @param name The name to use for the search. - * - * @return An RexxString version of the file name, iff the file was located. Returns - * OREF_NULL if the file did not exist. - */ -bool SysInterpreterInstance::checkCurrentFile(const char *name, char *resolvedName) -{ - size_t nameLength = strlen(name); /* get length of incoming name */ - - // make sure we have a valid length for even searching - if (nameLength < 1 || nameLength > CCHMAXPATH) - { - return false; - } - - // check the name in the current directory - unsigned int errorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - LPTSTR ppszFilePart=NULL; // file name only in buffer - - if (GetFullPathName(name, CCHMAXPATH, (LPTSTR)resolvedName, &ppszFilePart)) - { - DWORD fileAttrib = GetFileAttributes((LPTSTR)resolvedName); - - // if this is a real file vs. a directory, make sure we return - // the long name value in the correct casing - if (fileAttrib != INVALID_FILE_ATTRIBUTES && fileAttrib != FILE_ATTRIBUTE_DIRECTORY) - { - getLongName(resolvedName, CCHMAXPATH); - SetErrorMode(errorMode); - return true; - } - } - return false; // not found -} - - -/** - * Do a path search for a file. - * - * @param name The name to search for. - * @param path The search path to use. - * @param extension Any extension that should be added to the search (can be NULL). - * @param resolvedName - * A buffer used for returning the resolved name. - * - * @return Returns true if the file was located. If true, the resolvedName - * buffer will contain the returned name. - */ -bool SysInterpreterInstance::searchPath(const char *name, const char *path, const char *extension, char *resolvedName) -{ - unsigned int errorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - - LPTSTR ppszFilePart=NULL; // file name only in buffer - if (SearchPath((LPCTSTR)path, (LPCTSTR)name, (LPCTSTR)extension, CCHMAXPATH, (LPTSTR)resolvedName, &ppszFilePart)) - { - DWORD fileAttrib = GetFileAttributes((LPTSTR)resolvedName); - - // if this is a real file vs. a directory, make sure we return - // the long name value in the correct casing - if (fileAttrib != INVALID_FILE_ATTRIBUTES && fileAttrib != FILE_ATTRIBUTE_DIRECTORY) - { - getLongName(resolvedName, CCHMAXPATH); - SetErrorMode(errorMode); - return true; - } - } - return false; // not found -} - - -/** - * Get the actual name value of a located file, in the exact case - * used on the harddrive. - * - * @param fullName The buffer used for the name. - * @param size The size of the buffer. - */ -void SysInterpreterInstance::getLongName(char *fullName, size_t size) -{ - char *p; - - if (size >= CCHMAXPATH) - { - DWORD length = GetLongPathName(fullName, fullName, (DWORD)size); - - if ( 0 < length && length <= size ) - { - WIN32_FIND_DATA findData; - HANDLE hFind = FindFirstFile(fullName, &findData); - if ( hFind != INVALID_HANDLE_VALUE ) - { - p = strrchr(fullName, '\\'); - if ( p ) - { - strcpy(++p, findData . cFileName); - } - FindClose(hFind); - } - } - } - return; -} - void SystemInterpreter::loadImage( char **imageBuffer, /* returned start of the image */ size_t *imageSize ) /* size of the image */ Modified: interpreter-3.x/trunk/kernel/platform/windows/SysFileSystem.cpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/windows/SysFileSystem.cpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/windows/SysFileSystem.cpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -42,7 +42,7 @@ /* */ /******************************************************************************/ -#include "windows.h" +#include "RexxCore.h" #include "SysFileSystem.hpp" int SysFileSystem::stdinHandle = 0; @@ -206,3 +206,284 @@ return findFirstFile(name); } + + +/** + * Extract directory information from a file name. + * + * @param file The input file name. If this represents a real source file, + * this will be fully resolved. + * + * @return The directory portion of the file name. If the file name + * does not include a directory portion, then OREF_NULL is returned. + */ +RexxString *SysFileSystem::extractDirectory(RexxString *file) +{ + const char *pathName = file->getStringData(); + const char *endPtr = pathName + file->getLength() - 1; + + // scan backwards looking for a directory delimiter. This name should + // be fully qualified, so we don't have to deal with drive letters + while (pathName < endPtr) + { + // find the first directory element? + if (*endPtr == '\\') + { + // extract the directory information, including the final delimiter + // and return as a string object. + return new_string(pathName, endPtr - pathName + 1); + } + endPtr--; + } + return OREF_NULL; // not available +} + + +/** + * Extract extension information from a file name. + * + * @param file The input file name. If this represents a real source file, + * this will be fully resolved. + * + * @return The extension portion of the file name. If the file + * name does not include an extension portion, then + * OREF_NULL is returned. + */ +RexxString *SysFileSystem::extractExtension(RexxString *file) +{ + const char *pathName = file->getStringData(); + const char *endPtr = pathName + file->getLength() - 1; + + // scan backwards looking for a directory delimiter. This name should + // be fully qualified, so we don't have to deal with drive letters + while (pathName < endPtr) + { + // find the first directory element? + if (*endPtr == '\\') + { + return OREF_NULL; // found a directory portion before an extension...we're extensionless + } + // is this the extension dot? + else if (*endPtr == '.') + { + // return everything from the period on. Keeping the period on is a convenience. + return new_string(endPtr); + } + endPtr--; + } + return OREF_NULL; // not available +} + + +/** + * Extract file information from a file name. + * + * @param file The input file name. If this represents a real source file, + * this will be fully resolved. + * + * @return The file portion of the file name. If the file name + * does not include a directory portion, then the entire + * string is returned + */ +RexxString *SysFileSystem::extractFile(RexxString *file) +{ + const char *pathName = file->getStringData(); + const char *endPtr = pathName + file->getLength() - 1; + + // scan backwards looking for a directory delimiter. This name should + // be fully qualified, so we don't have to deal with drive letters + while (pathName < endPtr) + { + // find the first directory element? + if (*endPtr == '\\') + { + // extract the directory information, including the final delimiter + // and return as a string object. + return new_string(endPtr); + } + endPtr--; + } + return file; // this is all filename +} + + +/** + * Test if a filename has an extension. + * + * @param name The name to check. + * + * @return true if an extension was found on the file, false if there + * is no extension. + */ +bool SysFileSystem::hasExtension(const char *name) +{ + const char *endPtr = name + strlen(name) - 1; + + // scan backwards looking for a directory delimiter. This name should + // be fully qualified, so we don't have to deal with drive letters + while (name < endPtr) + { + // find the first directory element? + if (*endPtr == '/') + { + return false; // found a directory portion before an extension...we're extensionless + } + // is this the extension dot? + else if (*endPtr == '.') + { + // return everything from the period on. Keeping the period on is a convenience. + return true; + } + endPtr--; + } + return false; // not available +} + + +/** + * Do a search for a single variation of a filename. + * + * @param name The name to search for. + * @param directory A specific directory to look in first (can be NULL). + * @param extension A potential extension to add to the file name (can be NULL). + * @param resolvedName + * The buffer used to return the resolved file name. + * + * @return true if the file was located. A true returns indicates the + * resolved file name has been placed in the provided buffer. + */ +bool SysFileSystem::searchName(const char *name, const char *path, const char *extension, char *resolvedName) +{ + UnsafeBlock releaser; + // this is for building a temporary name + char tempName[CCHMAXPATH + 2]; + + // construct the search name, potentially adding on an extension + strncpy(tempName, name, sizeof(tempName)); + if (extension != NULL) + { + strncat(tempName, extension, sizeof(tempName)); + } + + // check the file as is first + if (checkCurrentFile(tempName, resolvedName)) + { + return true; + } + + *resolvedName = '\0'; + if (searchPath(name, path, extension, resolvedName)) + { + return true; + } + return false; +} + + + +/** + * Try to locate a file using just the raw name passed in, as + * opposed to searching along a path for the name. + * + * @param name The name to use for the search. + * + * @return An RexxString version of the file name, iff the file was located. Returns + * OREF_NULL if the file did not exist. + */ +bool SysFileSystem::checkCurrentFile(const char *name, char *resolvedName) +{ + size_t nameLength = strlen(name); /* get length of incoming name */ + + // make sure we have a valid length for even searching + if (nameLength < 1 || nameLength > CCHMAXPATH) + { + return false; + } + + // check the name in the current directory + unsigned int errorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + LPTSTR ppszFilePart=NULL; // file name only in buffer + + if (GetFullPathName(name, CCHMAXPATH, (LPTSTR)resolvedName, &ppszFilePart)) + { + DWORD fileAttrib = GetFileAttributes((LPTSTR)resolvedName); + + // if this is a real file vs. a directory, make sure we return + // the long name value in the correct casing + if (fileAttrib != INVALID_FILE_ATTRIBUTES && fileAttrib != FILE_ATTRIBUTE_DIRECTORY) + { + getLongName(resolvedName, CCHMAXPATH); + SetErrorMode(errorMode); + return true; + } + } + return false; // not found +} + + +/** + * Do a path search for a file. + * + * @param name The name to search for. + * @param path The search path to use. + * @param extension Any extension that should be added to the search (can be NULL). + * @param resolvedName + * A buffer used for returning the resolved name. + * + * @return Returns true if the file was located. If true, the resolvedName + * buffer will contain the returned name. + */ +bool SysFileSystem::searchPath(const char *name, const char *path, const char *extension, char *resolvedName) +{ + unsigned int errorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + + LPTSTR ppszFilePart=NULL; // file name only in buffer + if (SearchPath((LPCTSTR)path, (LPCTSTR)name, (LPCTSTR)extension, CCHMAXPATH, (LPTSTR)resolvedName, &ppszFilePart)) + { + DWORD fileAttrib = GetFileAttributes((LPTSTR)resolvedName); + + // if this is a real file vs. a directory, make sure we return + // the long name value in the correct casing + if (fileAttrib != INVALID_FILE_ATTRIBUTES && fileAttrib != FILE_ATTRIBUTE_DIRECTORY) + { + getLongName(resolvedName, CCHMAXPATH); + SetErrorMode(errorMode); + return true; + } + } + return false; // not found +} + + +/** + * Get the actual name value of a located file, in the exact case + * used on the harddrive. + * + * @param fullName The buffer used for the name. + * @param size The size of the buffer. + */ +void SysFileSystem::getLongName(char *fullName, size_t size) +{ + char *p; + + if (size >= CCHMAXPATH) + { + DWORD length = GetLongPathName(fullName, fullName, (DWORD)size); + + if ( 0 < length && length <= size ) + { + WIN32_FIND_DATA findData; + HANDLE hFind = FindFirstFile(fullName, &findData); + if ( hFind != INVALID_HANDLE_VALUE ) + { + p = strrchr(fullName, '\\'); + if ( p ) + { + strcpy(++p, findData . cFileName); + } + FindClose(hFind); + } + } + } + return; +} Modified: interpreter-3.x/trunk/kernel/platform/windows/SysFileSystem.hpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/windows/SysFileSystem.hpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/windows/SysFileSystem.hpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -36,7 +36,7 @@ /* */ /*----------------------------------------------------------------------------*/ /******************************************************************************/ -/* REXX Kernel SysThread.hpp */ +/* REXX Kernel SysFileSystem.hpp */ /* */ /* System support for FileSystem operations. */ /* */ @@ -48,6 +48,8 @@ #include "windows.h" #include <stdio.h> +class RexxString; + class SysFileSystem { public: @@ -71,6 +73,14 @@ static void qualifyStreamName(const char *unqualifiedName, char *qualifiedName, size_t bufferSize); static bool findFirstFile(const char *name); static bool fileExists(const char *name); + static bool hasExtension(const char *name); + static RexxString *extractDirectory(RexxString *file); + static RexxString *extractExtension(RexxString *file); + static RexxString *extractFile(RexxString *file); + static bool searchName(const char *name, const char *path, const char *extension, char *resolvedName); + static bool checkCurrentFile(const char *name, char *resolvedName); + static bool searchPath(const char *name, const char *path, const char *extension, char *resolvedName); + static void getLongName(char *fullName, size_t size); }; #endif Modified: interpreter-3.x/trunk/kernel/platform/windows/SysInterpreterInstance.hpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/windows/SysInterpreterInstance.hpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/windows/SysInterpreterInstance.hpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -55,12 +55,7 @@ RexxString *resolveProgramName(RexxString *_name, RexxString *_parentDir, RexxString *_parentExtension); protected: - bool hasExtension(const char *name); void addSearchExtension(const char *name); - bool searchName(const char *name, const char *path, const char *extension, char *resolvedName); - bool checkCurrentFile(const char *name, char *resolvedName); - bool searchPath(const char *name, const char *path, const char *extension, char *resolvedName); - void getLongName(char *fullName, size_t size); InterpreterInstance *instance; // backlink to our instance container }; Modified: interpreter-3.x/trunk/kernel/platform/windows/SystemInterpreter.hpp =================================================================== --- interpreter-3.x/trunk/kernel/platform/windows/SystemInterpreter.hpp 2008-07-05 12:19:10 UTC (rev 2659) +++ interpreter-3.x/trunk/kernel/platform/windows/SystemInterpreter.hpp 2008-07-05 13:04:39 UTC (rev 2660) @@ -75,9 +75,6 @@ static inline void setTimeSliceTimerThread(HANDLE h) { timeSliceTimerThread = h; } static bool loadMessage(wholenumber_t code, char *buffer, size_t bufferLength); - static RexxString *extractDirectory(RexxString *file); - static RexxString *extractExtension(Re... [truncated message content] |