zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob c45dbbb3 (4687B) - Raw


      1 /* basename.c
      2  *
      3  * $Id: basename.c,v 1.2 2007/03/08 23:15:58 keithmarshall Exp $
      4  *
      5  * Provides an implementation of the "basename" function, conforming
      6  * to SUSv3, with extensions to accommodate Win32 drive designators,
      7  * and suitable for use on native Microsoft(R) Win32 platforms.
      8  *
      9  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
     10  *
     11  * This is free software.  You may redistribute and/or modify it as you
     12  * see fit, without restriction of copyright.
     13  *
     14  * This software is provided "as is", in the hope that it may be useful,
     15  * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
     16  * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
     17  * time will the author accept any form of liability for any damages,
     18  * however caused, resulting from the use of this software.
     19  *
     20  */
     21 
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 #include <libgen.h>
     26 #include <locale.h>
     27 
     28 #ifndef __cdecl
     29 #define __cdecl
     30 #endif
     31 
     32 char * __cdecl
     33 basename (char *path)
     34 {
     35   static char *retfail = NULL;
     36   size_t len;
     37   /* to handle path names for files in multibyte character locales,
     38    * we need to set up LC_CTYPE to match the host file system locale
     39    */
     40   char *locale = setlocale (LC_CTYPE, NULL);
     41 
     42   if (locale != NULL)
     43     locale = strdup (locale);
     44   setlocale (LC_CTYPE, "");
     45 
     46   if (path && *path)
     47     {
     48       /* allocate sufficient local storage space,
     49        * in which to create a wide character reference copy of path
     50        */
     51       wchar_t refcopy[1 + (len = mbstowcs (NULL, path, 0))];
     52       /* create the wide character reference copy of path,
     53        * and step over the drive designator, if present ...
     54        */
     55       wchar_t *refpath = refcopy;
     56 
     57       if ((len = mbstowcs( refpath, path, len)) > 1 && refpath[1] == L':')
     58         {
     59 	  /* FIXME: maybe should confirm *refpath is a valid drive designator */
     60 	  refpath += 2;
     61         }
     62       /* ensure that our wide character reference path is NUL terminated */
     63       refcopy[len] = L'\0';
     64       /* check again, just to ensure we still have a non-empty path name ... */
     65       if (*refpath)
     66         {
     67 	  /* and, when we do, process it in the wide character domain ...
     68 	   * scanning from left to right, to the char after the final dir separator.  */
     69 	  wchar_t *refname;
     70 
     71 	  for (refname = refpath; *refpath; ++refpath)
     72 	    {
     73 	      if (*refpath == L'/' || *refpath == L'\\')
     74 	        {
     75 		  /* we found a dir separator ...
     76 		   * step over it, and any others which immediately follow it.  */
     77 		  while (*refpath == L'/' || *refpath == L'\\')
     78 		    ++refpath;
     79 		  /* if we didn't reach the end of the path string ... */
     80 		  if (*refpath)
     81 		    /* then we have a new candidate for the base name.  */
     82 		    refname = refpath;
     83 		  /* otherwise ...
     84 		   * strip off any trailing dir separators which we found.  */
     85 		  else
     86 		    while (refpath > refname
     87 		      && (*--refpath == L'/' || *refpath == L'\\')   )
     88 		      *refpath = L'\0';
     89 	        }
     90 	    }
     91 	  /* in the wide character domain ...
     92 	   * refname now points at the resolved base name ...  */
     93 	  if (*refname)
     94 	    {
     95 	      /* if it's not empty,
     96 	       * then we transform the full normalised path back into 
     97 	       * the multibyte character domain, and skip over the dirname,
     98 	       * to return the resolved basename.  */
     99 	      if ((len = wcstombs( path, refcopy, len)) != (size_t)(-1))
    100 		path[len] = '\0';
    101 	      *refname = L'\0';
    102 	      if ((len = wcstombs( NULL, refcopy, 0 )) != (size_t)(-1))
    103 		path += len;
    104 	    }
    105 	  else
    106 	    {
    107 	      /* the basename is empty, so return the default value of "/",
    108 	       * transforming from wide char to multibyte char domain, and
    109 	       * returning it in our own buffer.  */
    110 	      retfail = realloc (retfail, len = 1 + wcstombs (NULL, L"/", 0));
    111 	      wcstombs (path = retfail, L"/", len);
    112 	    }
    113 	  /* restore the caller's locale, clean up, and return the result */
    114 	  setlocale (LC_CTYPE, locale);
    115 	  free (locale);
    116 	  return path;
    117         }
    118       /* or we had an empty residual path name, after the drive designator,
    119        * in which case we simply fall through ...  */
    120     }
    121   /* and, if we get to here ...
    122    * the path name is either NULL, or it decomposes to an empty string;
    123    * in either case, we return the default value of "." in our own buffer,
    124    * reloading it with the correct value, transformed from the wide char
    125    * to the multibyte char domain, just in case the caller trashed it
    126    * after a previous call.
    127    */
    128   retfail = realloc (retfail, len = 1 + wcstombs( NULL, L".", 0));
    129   wcstombs (retfail, L".", len);
    130 
    131   /* restore the caller's locale, clean up, and return the result.  */
    132   setlocale (LC_CTYPE, locale);
    133   free (locale);
    134   return retfail;
    135 }