1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1992-2009 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 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,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