xref: /illumos-gate/usr/src/cmd/basename/basename.c (revision 2a8bcb4e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <locale.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #ifndef	XPG4
32 #include <unistd.h>
33 #include <regex.h>
34 #include <libintl.h>
35 #endif
36 
37 int
main(int argc,char ** argv)38 main(int argc, char **argv)
39 {
40 	char	*p;
41 	char	*string;
42 	char	*suffix;
43 #ifndef	XPG4
44 	int	r;
45 	char	suf_buf[256];
46 	char	*suf_pat;
47 	size_t	suf_len;
48 	regex_t	reg;
49 	regmatch_t	pmatch[2];
50 #endif
51 
52 	/*
53 	 * For better performance, defer the setlocale()/textdomain()
54 	 * calls until they get really required.
55 	 */
56 #if !defined(TEXT_DOMAIN)
57 #define	TEXT_DOMAIN "SYS_TEST"
58 #endif
59 	if (argc == 1) {
60 		(void) puts(".");
61 		return (0);
62 	}
63 
64 #ifdef	XPG4
65 	if (strcmp(argv[1], "--") == 0) {
66 		argv++;
67 		argc--;
68 		if (argc == 1) {
69 			(void) puts(".");
70 			return (0);
71 		}
72 	}
73 #endif
74 	if (argc > 3) {
75 		(void) setlocale(LC_ALL, "");
76 		(void) textdomain(TEXT_DOMAIN);
77 		(void) fputs(gettext("Usage: basename string [ suffix ]\n"),
78 		    stderr);
79 		return (1);
80 	}
81 
82 	string = argv[1];
83 	suffix = (argc == 2) ? NULL : argv[2];
84 
85 	if (*string == '\0') {
86 		(void) puts(".");
87 		return (0);
88 	}
89 
90 	/* remove trailing slashes */
91 	p = string + strlen(string) - 1;
92 	while (p >= string && *p == '/')
93 		*p-- = '\0';
94 
95 	if (*string == '\0') {
96 		(void) puts("/");
97 		return (0);
98 	}
99 
100 	/* skip to one past last slash */
101 	if ((p = strrchr(string, '/')) != NULL)
102 		string = p + 1;
103 
104 	if (suffix == NULL) {
105 		(void) puts(string);
106 		return (0);
107 	}
108 
109 #ifdef	XPG4
110 	/*
111 	 * if a suffix is present and is not the same as the remaining
112 	 * string and is identical to the last characters in the remaining
113 	 * string, remove those characters from the string.
114 	 */
115 	if (strcmp(string, suffix) != 0) {
116 		p = string + strlen(string) - strlen(suffix);
117 		if (strcmp(p, suffix) == 0)
118 			*p = '\0';
119 	}
120 	(void) puts(string);
121 	return (0);
122 #else
123 	(void) setlocale(LC_ALL, "");
124 	(void) textdomain(TEXT_DOMAIN);
125 
126 	suf_len = 6 + strlen(suffix) + 1 + 1; /* \(.*\)suffix$ */
127 	if (suf_len > sizeof (suf_buf)) {
128 		suf_pat = malloc(suf_len);
129 		if (suf_pat == NULL) {
130 			(void) fputs("malloc failed\n", stderr);
131 			return (1);
132 		}
133 	} else {
134 		suf_pat = suf_buf;
135 	}
136 	(void) strcpy(suf_pat, "\\(.*\\)");
137 	(void) strcpy(suf_pat + 6, suffix);
138 	*(suf_pat + suf_len - 1 - 1) = '$';
139 	*(suf_pat + suf_len - 1) = '\0';
140 
141 	r = regcomp(&reg, suf_pat, 0);
142 	if (r != 0) {
143 		(void) fprintf(stderr,
144 		    "Internal error: regcomp failed for \"%s\"\n",
145 		    suf_pat);
146 		return (1);
147 	}
148 	r = regexec(&reg, string, 2, pmatch, 0);
149 	if (r == 0) {
150 		if (pmatch[0].rm_so == (regoff_t)-1 ||
151 		    pmatch[1].rm_so == (regoff_t)-1 ||
152 		    pmatch[1].rm_so != 0) {
153 			(void) fprintf(stderr, "Internal error: regexec did "
154 			    "not set sub-expression for:\n");
155 			(void) fprintf(stderr, "path: \"%s\"\n", string);
156 			(void) fprintf(stderr, "pattern: \"%s\"", suf_pat);
157 			return (1);
158 		}
159 		if (pmatch[1].rm_so == pmatch[1].rm_eo) {
160 			/* a null string matched */
161 			(void) printf("%s\n", string);
162 			return (0);
163 		}
164 		string[pmatch[1].rm_eo] = '\0';
165 	}
166 	(void) puts(string);
167 	return (0);
168 #endif
169 }
170