1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1992-2010 AT&T Intellectual Property * 5* and is licensed under the * 6* Common Public License, Version 1.0 * 7* by AT&T Intellectual Property * 8* * 9* A copy of the License is available at * 10* http://www.opensource.org/licenses/cpl1.0.txt * 11* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12* * 13* Information and Software Systems Research * 14* AT&T Research * 15* Florham Park NJ * 16* * 17* Glenn Fowler <gsf@research.att.com> * 18* David Korn <dgk@research.att.com> * 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 31static const char usage[] = 32"[-?\n@(#)$Id: dirname (AT&T Research) 2009-01-31 $\n]" 33USAGE_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 66static 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 98int 99b_dirname(int argc,register char *argv[], void* context) 100{ 101 register int n; 102 int mode = 0; 103 char buf[PATH_MAX]; 104 105 cmdinit(argc, argv, context, ERROR_CATALOG, 0); 106 while (n = optget(argv, usage)) switch (n) 107 { 108 case 'f': 109 mode |= PATH_REGULAR; 110 break; 111 case 'r': 112 mode &= ~PATH_REGULAR; 113 mode |= PATH_READ; 114 break; 115 case 'x': 116 mode |= PATH_EXECUTE; 117 break; 118 case ':': 119 error(2, "%s", opt_info.arg); 120 break; 121 case '?': 122 error(ERROR_usage(2), "%s", opt_info.arg); 123 break; 124 } 125 argv += opt_info.index; 126 argc -= opt_info.index; 127 if(error_info.errors || argc != 1) 128 error(ERROR_usage(2),"%s", optusage(NiL)); 129 if(!mode) 130 l_dirname(sfstdout,argv[0]); 131 else if(pathpath(buf, argv[0], "", mode)) 132 sfputr(sfstdout, buf, '\n'); 133 else 134 error(1|ERROR_WARNING, "%s: relative path not found", argv[0]); 135 return(0); 136} 137