From 724dbeea36fd72b07123431c3c2c3fd1c059c5ec Mon Sep 17 00:00:00 2001 From: Keith Marshall Date: Sun, 31 Dec 2006 18:03:33 +0000 Subject: [PATCH] * include/libgen.h: New file; required by... * mingwex/basename.c, mingwex/dirname.c: New files. * mingwex/Makefile.in (DISTFILES): Add them... (POSIX_OBJS): ...with corresponding basename.o, dirname.o (Dependencies): Typo; s/Dependancies/Dependencies/ --- winsup/mingw/ChangeLog | 8 ++ winsup/mingw/include/libgen.h | 31 ++++++ winsup/mingw/mingwex/Makefile.in | 8 +- winsup/mingw/mingwex/basename.c | 103 ++++++++++++++++++ winsup/mingw/mingwex/dirname.c | 174 +++++++++++++++++++++++++++++++ 5 files changed, 321 insertions(+), 3 deletions(-) create mode 100755 winsup/mingw/include/libgen.h create mode 100755 winsup/mingw/mingwex/basename.c create mode 100755 winsup/mingw/mingwex/dirname.c diff --git a/winsup/mingw/ChangeLog b/winsup/mingw/ChangeLog index 0b5685ba4..4d5c0e09e 100644 --- a/winsup/mingw/ChangeLog +++ b/winsup/mingw/ChangeLog @@ -1,3 +1,11 @@ +2006-12-31 Keith Marshall + + * include/libgen.h: New file; required by... + * mingwex/basename.c, mingwex/dirname.c: New files. + * mingwex/Makefile.in (DISTFILES): Add them... + (POSIX_OBJS): ...with corresponding basename.o, dirname.o + (Dependencies): Typo; s/Dependancies/Dependencies/ + 2006-11-25 Keith Marshall * Makefile.in (VERSION): Let configure define it. diff --git a/winsup/mingw/include/libgen.h b/winsup/mingw/include/libgen.h new file mode 100755 index 000000000..cf4793bb7 --- /dev/null +++ b/winsup/mingw/include/libgen.h @@ -0,0 +1,31 @@ +#ifndef _LIBGEN_H_ +/* + * libgen.h + * + * $Id$ + * + * This file has no copyright assigned and is placed in the Public Domain. + * This file is a part of the mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within the package. + * + * Functions for splitting pathnames into dirname and basename components. + * + */ +#define _LIBGEN_H_ + +/* All the headers include this file. */ +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern __cdecl char *basename (char *); +extern __cdecl char *dirname (char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBGEN_H_: end of file */ + diff --git a/winsup/mingw/mingwex/Makefile.in b/winsup/mingw/mingwex/Makefile.in index 8775c3235..a8e007dae 100644 --- a/winsup/mingw/mingwex/Makefile.in +++ b/winsup/mingw/mingwex/Makefile.in @@ -36,7 +36,8 @@ DISTFILES = Makefile.in configure configure.in aclocal.m4 \ wcstoimax.c wcstold.c wcstoumax.c wctrans.c wctype.c \ wdirent.c wmemchr.c wmemcmp.c wmemcpy.c wmemmove.c wmemset.c wtoll.c \ wcrtomb.c wctob.c mbrtowc.c btowc.c mb_wc_common.h \ - gettimeofday.c isblank.c iswblank.c + gettimeofday.c isblank.c iswblank.c \ + basename.c dirname.c MATH_DISTFILES = \ acosf.c acosl.c asinf.c asinl.c atan2f.c atan2l.c \ @@ -172,7 +173,8 @@ FENV_OBJS = fesetround.o fegetround.o \ feclearexcept.o feholdexcept.o fegetexceptflag.o \ feraiseexcept.o fetestexcept.o fesetexceptflag.o POSIX_OBJS = \ - dirent.o wdirent.o getopt.o ftruncate.o gettimeofday.o + dirent.o wdirent.o getopt.o ftruncate.o gettimeofday.o \ + basename.o dirname.o REPLACE_OBJS = \ mingw-aligned-malloc.o mingw-fseek.o COMPLEX_OBJS = \ @@ -238,7 +240,7 @@ distclean: # -# Dependancies +# Dependencies # wdirent.o: $(srcdir)/dirent.c $(srcdir)/wdirent.c diff --git a/winsup/mingw/mingwex/basename.c b/winsup/mingw/mingwex/basename.c new file mode 100755 index 000000000..768b9a0f4 --- /dev/null +++ b/winsup/mingw/mingwex/basename.c @@ -0,0 +1,103 @@ +/* basename.c + * + * $Id$ + * + * Provides an implementation of the "basename" function, conforming + * to SUSv3, with extensions to accommodate Win32 drive designators, + * and suitable for use on native Microsoft(R) Win32 platforms. + * + * Written by Keith Marshall + * + * This is free software. You may redistribute and/or modify it as you + * see fit, without restriction of copyright. + * + * This software is provided "as is", in the hope that it may be useful, + * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of + * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no + * time will the author accept any form of liability for any damages, + * however caused, resulting from the use of this software. + * + */ + +#include +#include +#include + +#ifndef __cdecl /* If compiling on any non-Win32 platform ... */ +#define __cdecl /* this may not be defined. */ +#endif + +__cdecl char *basename( char *path ) +{ + char *retname; + static char retfail[] = "."; + + if( path && *path ) + { + /* step over the drive designator, if present ... + * (FIXME: maybe should confirm *path is a valid drive designator). + */ + + if( path[1] == ':' ) + path += 2; + + /* check again, just to ensure we still have a non-empty path name ... */ + + if( *path ) + { + /* and, when we do ... + * scan from left to right, to the char after the final dir separator + */ + + for( retname = path ; *path ; ++path ) + { + if( (*path == '/') || (*path == '\\') ) + { + /* we found a dir separator ... + * step over it, and any others which immediately follow it + */ + + while( (*path == '/') || (*path == '\\') ) + ++path; + + /* if we didn't reach the end of the path string ... */ + + if( *path ) + + /* then we have a new candidate for the base name */ + + retname = path; + + /* otherwise ... + * strip off any trailing dir separators which we found + */ + + else while( (path > retname) && ((*--path == '/') || (*path == '\\')) ) + *path = '\0'; + } + } + + /* retname now points at the resolved base name ... + * if it's not empty, then we return it as it is, otherwise ... + * we must have had only dir separators in the original path name, + * so we return "/". + */ + + return *retname ? retname : strcpy( retfail, "/" ); + } + + /* or we had an empty residual path name, after the drive designator, + * in which case we simply fall through ... + */ + } + + /* and, if we get to here ... + * the path name is either NULL, or it decomposes to an empty string; + * in either case, we return the default value of "." in our static buffer, + * (but strcpy it, just in case the caller trashed it after a previous call). + */ + + return strcpy( retfail, "." ); +} + +/* $RCSfile$: end of file */ diff --git a/winsup/mingw/mingwex/dirname.c b/winsup/mingw/mingwex/dirname.c new file mode 100755 index 000000000..44256b19c --- /dev/null +++ b/winsup/mingw/mingwex/dirname.c @@ -0,0 +1,174 @@ +/* dirname.c + * + * $Id$ + * + * Provides an implementation of the "dirname" function, conforming + * to SUSv3, with extensions to accommodate Win32 drive designators, + * and suitable for use on native Microsoft(R) Win32 platforms. + * + * Written by Keith Marshall + * + * This is free software. You may redistribute and/or modify it as you + * see fit, without restriction of copyright. + * + * This software is provided "as is", in the hope that it may be useful, + * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of + * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no + * time will the author accept any form of liability for any damages, + * however caused, resulting from the use of this software. + * + */ + +#include +#include +#include + +#ifndef __cdecl /* If compiling on any non-Win32 platform ... */ +#define __cdecl /* this may not be defined. */ +#endif + +__cdecl char *dirname( char *path ) +{ + static char retfail[] = "?:."; + char *retname, *basename, *copyptr = retfail; + + if( path && *path ) + { + retname = path; + + /* SUSv3 identifies a special case, where path is exactly equal to "//"; + * (we will also accept "\\" in the Win32 context, but not "/\" or "\/", + * and neither will we consider paths with an initial drive designator). + * For this special case, SUSv3 allows the implementation to choose to + * return "/" or "//", (or "\" or "\\", since this is Win32); we will + * simply return the path unchanged, (i.e. "//" or "\\"). + */ + + if( (*path == '/') || (*path == '\\') ) + { + if( (path[1] == *retname) && (path[2] == '\0') ) + return retname; + } + + /* For all other cases ... + * step over the drive designator, if present, copying it to retfail ... + * (FIXME: maybe should confirm *path is a valid drive designator). + */ + + else if( *path && (path[1] == ':') ) + { + *copyptr++ = *path++; + *copyptr++ = *path++; + } + + if( *path ) + { + /* reproduce the scanning logic of the "basename" function + * to locate the basename component of the current path string, + * (but also remember where the dirname component starts). + */ + + for( retname = basename = path ; *path ; ++path ) + { + if( (*path == '/') || (*path == '\\') ) + { + /* we found a dir separator ... + * step over it, and any others which immediately follow it + */ + + while( (*path == '/') || (*path == '\\') ) + ++path; + + /* if we didn't reach the end of the path string ... */ + + if( *path ) + + /* then we have a new candidate for the base name */ + + basename = path; + + else + + /* we struck an early termination of the path string, + * with trailing dir separators following the base name, + * so break out of the for loop, to avoid overrun. + */ + + break; + } + } + + /* now check, + * to confirm that we have distinct dirname and basename components + */ + + if( basename > retname ) + { + /* and, when we do ... + * backtrack over all trailing separators on the dirname component, + * (but preserve exactly two initial dirname separators, if identical), + * and add a NULL terminator in their place. + */ + + --basename; + while( (basename > retname) && ((*basename == '/') || (*basename == '\\')) ) + --basename; + if( (basename == retname) && ((*retname == '/') || (*retname == '\\')) + && (retname[1] == *retname) && (retname[2] != '/') && (retname[2] != '\\') ) + ++basename; + *++basename = '\0'; + + /* adjust the start point of the dirname, + * to accommodate the Win32 drive designator, if it was present. + */ + + if( copyptr > retfail ) + retname -= 2; + + /* if the resultant dirname begins with EXACTLY two dir separators, + * AND both are identical, then we preserve them. + */ + + path = copyptr = retname; + while( ((*path == '/') || (*path == '\\')) ) + ++path; + if( ((path - retname) == 2) && (*++copyptr == *retname) ) + ++copyptr; + + /* and finally ... + * we remove any residual, redundantly duplicated separators from the dirname, + * reterminate, and return it. + */ + + path = copyptr; + while( *path ) + { + if( ((*copyptr++ = *path) == '/') || (*path++ == '\\') ) + { + while( (*path == '/') || (*path == '\\') ) + ++path; + } + } + *copyptr = '\0'; + return retname; + } + + else if( (*retname == '/') || (*retname == '\\') ) + { + *copyptr++ = *retname; + *copyptr = '\0'; + return retfail; + } + } + } + + /* path is NULL, or an empty string; default return value is "." ... + * return this in our own static buffer, but strcpy it, just in case + * the caller trashed it after a previous call. + */ + + strcpy( copyptr, "." ); + return retfail; +} + +/* $RCSfile$: end of file */