xref: /illumos-gate/usr/src/cmd/basename/basename.c (revision 734b6a94890be549309b21156f8ed6d4561cac51)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <locale.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #ifndef	XPG4
34 #include <unistd.h>
35 #include <regex.h>
36 #include <libintl.h>
37 #endif
38 
39 int
40 main(int argc, char **argv)
41 {
42 	char	*p;
43 	char	*string;
44 	char	*suffix;
45 #ifndef	XPG4
46 	int	r;
47 	char	suf_buf[256];
48 	char	*suf_pat;
49 	size_t	suf_len;
50 	regex_t	reg;
51 	regmatch_t	pmatch[2];
52 #endif
53 
54 	/*
55 	 * For better performance, defer the setlocale()/textdomain()
56 	 * calls until they get really required.
57 	 */
58 #if !defined(TEXT_DOMAIN)
59 #define	TEXT_DOMAIN "SYS_TEST"
60 #endif
61 	if (argc == 1) {
62 		(void) puts(".");
63 		return (0);
64 	}
65 
66 #ifdef	XPG4
67 	if (strcmp(argv[1], "--") == 0) {
68 		argv++;
69 		argc--;
70 		if (argc == 1) {
71 			(void) puts(".");
72 			return (0);
73 		}
74 	}
75 #endif
76 	if (argc > 3) {
77 		(void) setlocale(LC_ALL, "");
78 		(void) textdomain(TEXT_DOMAIN);
79 		(void) fputs(gettext("Usage: basename string [ suffix ]\n"),
80 		    stderr);
81 		return (1);
82 	}
83 
84 	string = argv[1];
85 	suffix = (argc == 2) ? NULL : argv[2];
86 
87 	if (*string == '\0') {
88 		(void) puts(".");
89 		return (0);
90 	}
91 
92 	/* remove trailing slashes */
93 	p = string + strlen(string) - 1;
94 	while (p >= string && *p == '/')
95 		*p-- = '\0';
96 
97 	if (*string == '\0') {
98 		(void) puts("/");
99 		return (0);
100 	}
101 
102 	/* skip to one past last slash */
103 	if ((p = strrchr(string, '/')) != NULL)
104 		string = p + 1;
105 
106 	if (suffix == NULL) {
107 		(void) puts(string);
108 		return (0);
109 	}
110 
111 #ifdef	XPG4
112 	/*
113 	 * if a suffix is present and is not the same as the remaining
114 	 * string and is identical to the last characters in the remaining
115 	 * string, remove those characters from the string.
116 	 */
117 	if (strcmp(string, suffix) != 0) {
118 		p = string + strlen(string) - strlen(suffix);
119 		if (strcmp(p, suffix) == 0)
120 			*p = '\0';
121 	}
122 	(void) puts(string);
123 	return (0);
124 #else
125 	(void) setlocale(LC_ALL, "");
126 	(void) textdomain(TEXT_DOMAIN);
127 
128 	suf_len = 6 + strlen(suffix) + 1 + 1; /* \(.*\)suffix$ */
129 	if (suf_len > sizeof (suf_buf)) {
130 		suf_pat = malloc(suf_len);
131 		if (suf_pat == NULL) {
132 			(void) fputs("malloc failed\n", stderr);
133 			return (1);
134 		}
135 	} else {
136 		suf_pat = suf_buf;
137 	}
138 	(void) strcpy(suf_pat, "\\(.*\\)");
139 	(void) strcpy(suf_pat + 6, suffix);
140 	*(suf_pat + suf_len - 1 - 1) = '$';
141 	*(suf_pat + suf_len - 1) = '\0';
142 
143 	r = regcomp(&reg, suf_pat, 0);
144 	if (r != 0) {
145 		(void) fprintf(stderr,
146 		    "Internal error: regcomp failed for \"%s\"\n",
147 		    suf_pat);
148 		return (1);
149 	}
150 	r = regexec(&reg, string, 2, pmatch, 0);
151 	if (r == 0) {
152 		if (pmatch[0].rm_so == (regoff_t)-1 ||
153 		    pmatch[1].rm_so == (regoff_t)-1 ||
154 		    pmatch[1].rm_so != 0) {
155 			(void) fprintf(stderr, "Internal error: regexec did "
156 			    "not set sub-expression for:\n");
157 			(void) fprintf(stderr, "path: \"%s\"\n", string);
158 			(void) fprintf(stderr, "pattern: \"%s\"", suf_pat);
159 			return (1);
160 		}
161 		if (pmatch[1].rm_so == pmatch[1].rm_eo) {
162 			/* a null string matched */
163 			(void) printf("%s\n", string);
164 			return (0);
165 		}
166 		string[pmatch[1].rm_eo] = '\0';
167 	}
168 	(void) puts(string);
169 	return (0);
170 #endif
171 }
172