Logo Search packages:      
Sourcecode: mingw-w64 version File versions

basename.c

/* basename.c
 *
 * $Id: basename.c,v 1.2 2007/03/08 23:15:58 keithmarshall Exp $
 *
 * 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 <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <locale.h>

#ifndef __cdecl
#define __cdecl
#endif

char * __cdecl
basename (char *path)
{
  static char *retfail = NULL;
  size_t len;
  /* to handle path names for files in multibyte character locales,
   * we need to set up LC_CTYPE to match the host file system locale
   */
  char *locale = setlocale (LC_CTYPE, NULL);

  if (locale != NULL)
    locale = strdup (locale);
  setlocale (LC_CTYPE, "");

  if (path && *path)
    {
      /* allocate sufficient local storage space,
       * in which to create a wide character reference copy of path
       */
      wchar_t refcopy[1 + (len = mbstowcs (NULL, path, 0))];
      /* create the wide character reference copy of path,
       * and step over the drive designator, if present ...
       */
      wchar_t *refpath = refcopy;

      if ((len = mbstowcs( refpath, path, len)) > 1 && refpath[1] == L':')
        {
        /* FIXME: maybe should confirm *refpath is a valid drive designator */
        refpath += 2;
        }
      /* ensure that our wide character reference path is NUL terminated */
      refcopy[len] = L'\0';
      /* check again, just to ensure we still have a non-empty path name ... */
      if (*refpath)
        {
        /* and, when we do, process it in the wide character domain ...
         * scanning from left to right, to the char after the final dir separator.  */
        wchar_t *refname;

        for (refname = refpath; *refpath; ++refpath)
          {
            if (*refpath == L'/' || *refpath == L'\\')
              {
              /* we found a dir separator ...
               * step over it, and any others which immediately follow it.  */
              while (*refpath == L'/' || *refpath == L'\\')
                ++refpath;
              /* if we didn't reach the end of the path string ... */
              if (*refpath)
                /* then we have a new candidate for the base name.  */
                refname = refpath;
              /* otherwise ...
               * strip off any trailing dir separators which we found.  */
              else
                while (refpath > refname
                  && (*--refpath == L'/' || *refpath == L'\\')   )
                  *refpath = L'\0';
              }
          }
        /* in the wide character domain ...
         * refname now points at the resolved base name ...  */
        if (*refname)
          {
            /* if it's not empty,
             * then we transform the full normalised path back into 
             * the multibyte character domain, and skip over the dirname,
             * to return the resolved basename.  */
            if ((len = wcstombs( path, refcopy, len)) != (size_t)(-1))
            path[len] = '\0';
            *refname = L'\0';
            if ((len = wcstombs( NULL, refcopy, 0 )) != (size_t)(-1))
            path += len;
          }
        else
          {
            /* the basename is empty, so return the default value of "/",
             * transforming from wide char to multibyte char domain, and
             * returning it in our own buffer.  */
            retfail = realloc (retfail, len = 1 + wcstombs (NULL, L"/", 0));
            wcstombs (path = retfail, L"/", len);
          }
        /* restore the caller's locale, clean up, and return the result */
        setlocale (LC_CTYPE, locale);
        free (locale);
        return path;
        }
      /* 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 own buffer,
   * reloading it with the correct value, transformed from the wide char
   * to the multibyte char domain, just in case the caller trashed it
   * after a previous call.
   */
  retfail = realloc (retfail, len = 1 + wcstombs( NULL, L".", 0));
  wcstombs (retfail, L".", len);

  /* restore the caller's locale, clean up, and return the result.  */
  setlocale (LC_CTYPE, locale);
  free (locale);
  return retfail;
}

Generated by  Doxygen 1.6.0   Back to index