Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: sane_basename.c,v 1.1.1.1 2009/06/23 10:09:00 tron Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	sane_basename 3
      6 /* SUMMARY
      7 /*	split pathname into last component and parent directory
      8 /* SYNOPSIS
      9 /*	#include <stringops.h>
     10 /*
     11 /*	char	*sane_basename(buf, path)
     12 /*	VSTRING	*buf;
     13 /*	const char *path;
     14 /*
     15 /*	char	*sane_dirname(buf, path)
     16 /*	VSTRING	*buf;
     17 /*	const char *path;
     18 /* DESCRIPTION
     19 /*	These functions split a pathname into its last component
     20 /*	and its parent directory, excluding any trailing "/"
     21 /*	characters from the input. The result is a pointer to "/"
     22 /*	when the input is all "/" characters, or a pointer to "."
     23 /*	when the input is a null pointer or zero-length string.
     24 /*
     25 /*	sane_basename() and sane_dirname() differ as follows
     26 /*	from standard basename() and dirname() implementations:
     27 /* .IP \(bu
     28 /*	They can use caller-provided storage or private storage.
     29 /* .IP \(bu
     30 /*	They never modify their input.
     31 /* .PP
     32 /*	sane_basename() returns a pointer to string with the last
     33 /*	pathname component.
     34 /*
     35 /*	sane_dirname() returns a pointer to string with the parent
     36 /*	directory. The result is a pointer to "." when the input
     37 /*	contains no '/' character.
     38 /*
     39 /*	Arguments:
     40 /* .IP buf
     41 /*	Result storage. If a null pointer is specified, each function
     42 /*	uses its own private memory that is overwritten upon each call.
     43 /* .IP path
     44 /*	The input pathname.
     45 /* LICENSE
     46 /* .ad
     47 /* .fi
     48 /*	The Secure Mailer license must be distributed with this
     49 /*	software.
     50 /* AUTHOR(S)
     51 /*	Wietse Venema
     52 /*	IBM T.J. Watson Research
     53 /*	P.O. Box 704
     54 /*	Yorktown Heights, NY 10598, USA
     55 /*--*/
     56 
     57 /* System library. */
     58 
     59 #include <sys_defs.h>
     60 #include <string.h>
     61 
     62 /* Utility library. */
     63 
     64 #include <vstring.h>
     65 #include <stringops.h>
     66 
     67 #define STR(x)	vstring_str(x)
     68 
     69 /* sane_basename - skip directory prefix */
     70 
     71 char   *sane_basename(VSTRING *bp, const char *path)
     72 {
     73     static VSTRING *buf;
     74     const char *first;
     75     const char *last;
     76 
     77     /*
     78      * Your buffer or mine?
     79      */
     80     if (bp == 0) {
     81 	bp = buf;
     82 	if (bp == 0)
     83 	    bp = buf = vstring_alloc(10);
     84     }
     85 
     86     /*
     87      * Special case: return "." for null or zero-length input.
     88      */
     89     if (path == 0 || *path == 0)
     90 	return (STR(vstring_strcpy(bp, ".")));
     91 
     92     /*
     93      * Remove trailing '/' characters from input. Return "/" if input is all
     94      * '/' characters.
     95      */
     96     last = path + strlen(path) - 1;
     97     while (*last == '/') {
     98 	if (last == path)
     99 	    return (STR(vstring_strcpy(bp, "/")));
    100 	last--;
    101     }
    102 
    103     /*
    104      * The pathname does not end in '/'. Skip to last '/' character if any.
    105      */
    106     first = last - 1;
    107     while (first >= path && *first != '/')
    108 	first--;
    109 
    110     return (STR(vstring_strncpy(bp, first + 1, last - first)));
    111 }
    112 
    113 /* sane_dirname - keep directory prefix */
    114 
    115 char   *sane_dirname(VSTRING *bp, const char *path)
    116 {
    117     static VSTRING *buf;
    118     const char *last;
    119 
    120     /*
    121      * Your buffer or mine?
    122      */
    123     if (bp == 0) {
    124 	bp = buf;
    125 	if (bp == 0)
    126 	    bp = buf = vstring_alloc(10);
    127     }
    128 
    129     /*
    130      * Special case: return "." for null or zero-length input.
    131      */
    132     if (path == 0 || *path == 0)
    133 	return (STR(vstring_strcpy(bp, ".")));
    134 
    135     /*
    136      * Remove trailing '/' characters from input. Return "/" if input is all
    137      * '/' characters.
    138      */
    139     last = path + strlen(path) - 1;
    140     while (*last == '/') {
    141 	if (last == path)
    142 	    return (STR(vstring_strcpy(bp, "/")));
    143 	last--;
    144     }
    145 
    146     /*
    147      * This pathname does not end in '/'. Skip to last '/' character if any.
    148      */
    149     while (last >= path && *last != '/')
    150 	last--;
    151     if (last < path)				/* no '/' */
    152 	return (STR(vstring_strcpy(bp, ".")));
    153 
    154     /*
    155      * Strip trailing '/' characters from dirname (not strictly needed).
    156      */
    157     while (last > path && *last == '/')
    158 	last--;
    159 
    160     return (STR(vstring_strncpy(bp, path, last - path + 1)));
    161 }
    162 
    163 #ifdef TEST
    164 #include <vstring_vstream.h>
    165 
    166 int     main(int argc, char **argv)
    167 {
    168     VSTRING *buf = vstring_alloc(10);
    169     char   *dir;
    170     char   *base;
    171 
    172     while (vstring_get_nonl(buf, VSTREAM_IN) > 0) {
    173 	dir = sane_dirname((VSTRING *) 0, STR(buf));
    174 	base = sane_basename((VSTRING *) 0, STR(buf));
    175 	vstream_printf("input=\"%s\" dir=\"%s\" base=\"%s\"\n",
    176 		       STR(buf), dir, base);
    177     }
    178     vstream_fflush(VSTREAM_OUT);
    179     vstring_free(buf);
    180     return (0);
    181 }
    182 
    183 #endif
    184