Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcmd/dirname.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1992-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* *
20
***********************************************************************/
21
#pragma prototyped
22
/*
23
* David Korn
24
* AT&T Bell Laboratories
25
*
26
* dirname path [suffix]
27
*
28
* print the dirname of a pathname
29
*/
30
31
static const char usage[] =
32
"[-?\n@(#)$Id: dirname (AT&T Research) 2009-01-31 $\n]"
33
USAGE_LICENSE
34
"[+NAME?dirname - return directory portion of file name]"
35
"[+DESCRIPTION?\bdirname\b treats \astring\a as a file name and returns "
36
"the name of the directory containing the file name by deleting "
37
"the last component from \astring\a.]"
38
"[+?If \astring\a consists solely of \b/\b characters the output will "
39
"be a single \b/\b unless \bPATH_LEADING_SLASHES\b returned by "
40
"\bgetconf\b(1) is \b1\b and \astring\a consists of multiple "
41
"\b/\b characters in which case \b//\b will be output. "
42
"Otherwise, trailing \b/\b characters are removed, and if "
43
"there are no remaining \b/\b characters in \astring\a, "
44
"the string \b.\b will be written to standard output. "
45
"Otherwise, all characters following the last \b/\b are removed. "
46
"If the remaining string consists solely of \b/\b characters, "
47
"the output will be as if the original string had consisted solely "
48
"as \b/\b characters as described above. Otherwise, all "
49
"trailing slashes are removed and the output will be this string "
50
"unless this string is empty. If empty the output will be \b.\b.]"
51
"[f:file?Print the \b$PATH\b relative regular file path for \astring\a.]"
52
"[r:relative?Print the \b$PATH\b relative readable file path for \astring\a.]"
53
"[x:executable?Print the \b$PATH\b relative executable file path for \astring\a.]"
54
"\n"
55
"\nstring\n"
56
"\n"
57
"[+EXIT STATUS?]{"
58
"[+0?Successful Completion.]"
59
"[+>0?An error occurred.]"
60
"}"
61
"[+SEE ALSO?\bbasename\b(1), \bgetconf\b(1), \bdirname\b(3), \bpathname\b(3)]"
62
;
63
64
#include <cmd.h>
65
66
static void l_dirname(register Sfio_t *outfile, register const char *pathname)
67
{
68
register const char *last;
69
/* go to end of path */
70
for(last=pathname; *last; last++);
71
/* back over trailing '/' */
72
while(last>pathname && *--last=='/');
73
/* back over non-slash chars */
74
for(;last>pathname && *last!='/';last--);
75
if(last==pathname)
76
{
77
/* all '/' or "" */
78
if(*pathname!='/')
79
last = pathname = ".";
80
}
81
else
82
{
83
/* back over trailing '/' */
84
for(;*last=='/' && last > pathname; last--);
85
}
86
/* preserve // */
87
if(last!=pathname && pathname[0]=='/' && pathname[1]=='/')
88
{
89
while(pathname[2]=='/' && pathname<last)
90
pathname++;
91
if(last!=pathname && pathname[0]=='/' && pathname[1]=='/' && *astconf("PATH_LEADING_SLASHES",NiL,NiL)!='1')
92
pathname++;
93
}
94
sfwrite(outfile,pathname,last+1-pathname);
95
sfputc(outfile,'\n');
96
}
97
98
int
99
b_dirname(int argc, char** argv, Shbltin_t* context)
100
{
101
int mode = 0;
102
char buf[PATH_MAX];
103
104
cmdinit(argc, argv, context, ERROR_CATALOG, 0);
105
for (;;)
106
{
107
switch (optget(argv, usage))
108
{
109
case 'f':
110
mode |= PATH_REGULAR;
111
continue;
112
case 'r':
113
mode &= ~PATH_REGULAR;
114
mode |= PATH_READ;
115
continue;
116
case 'x':
117
mode |= PATH_EXECUTE;
118
continue;
119
case ':':
120
error(2, "%s", opt_info.arg);
121
break;
122
case '?':
123
error(ERROR_usage(2), "%s", opt_info.arg);
124
break;
125
}
126
break;
127
}
128
argv += opt_info.index;
129
argc -= opt_info.index;
130
if(error_info.errors || argc != 1)
131
error(ERROR_usage(2),"%s", optusage(NiL));
132
if(!mode)
133
l_dirname(sfstdout,argv[0]);
134
else if(pathpath(argv[0], "", mode, buf, sizeof(buf)))
135
sfputr(sfstdout, buf, '\n');
136
else
137
error(1|ERROR_WARNING, "%s: relative path not found", argv[0]);
138
return 0;
139
}
140
141