From 724dbeea36fd72b07123431c3c2c3fd1c059c5ec Mon Sep 17 00:00:00 2001
From: Keith Marshall <keithmarshall@@users.sf.net>
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  <keithmarshall@users.sourceforge.net>
+
+	* 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  <keithmarshall@users.sourceforge.net>
 
 	* 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 <keithmarshall@users.sourceforge.net>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <libgen.h>
+
+#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 <keithmarshall@users.sourceforge.net>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <libgen.h>
+
+#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 */