dvitomp fix from Akira
[mplib] / src / texk / kpathsea / tilde.c
1 /* tilde.c: expand user's home directories.
2
3     Copyright 1997, 1998, 2005, Olaf Weber.
4     Copyright 1993, 1995, 1996, 1997, 2008 Karl Berry.
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Lesser General Public
8     License as published by the Free Software Foundation; either
9     version 2.1 of the License, or (at your option) any later version.
10
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public License
17    along with this library; if not, see <http://www.gnu.org/licenses/>.  */
18
19 #include <kpathsea/config.h>
20
21 #include <kpathsea/c-pathch.h>
22 #include <kpathsea/tilde.h>
23
24 #ifdef HAVE_PWD_H
25 #include <pwd.h>
26 #endif
27
28 #ifdef WIN32
29 #define HOMEVAR "USERPROFILE"
30 #else
31 #define HOMEVAR "HOME"
32 #endif
33
34 /* If NAME has a leading ~ or ~user, Unix-style, expand it to the user's
35    home directory, and return a new malloced string.  If no ~, or no
36    <pwd.h>, just return NAME.  */
37
38 string
39 kpse_tilde_expand P1C(const_string, name)
40 {
41   const_string expansion;
42   const_string home;
43   const_string prefix;
44   
45   assert (name);
46
47   /* If there is a leading "!!", set prefix to "!!", otherwise use
48      the empty string.  After this, we can test whether a prefix was
49      found by checking *prefix, and it is safe to unconditionally
50      prepend it. */
51   if (name[0] == '!' && name[1] == '!') {
52     name += 2;
53     prefix = "!!";
54   } else {
55     prefix = "";
56   }
57   
58   /* If no leading tilde, do nothing, and return the original string.  */
59   if (*name != '~') {
60     if (*prefix)
61       name -= 2;
62     expansion = name;
63   
64   /* If a bare tilde, return the home directory or `.'.  (Very unlikely
65      that the directory name will do anyone any good, but ...  */
66   } else if (name[1] == 0) {
67     home = getenv (HOMEVAR);
68     if (!home) {
69       home = ".";
70     }
71     expansion = concat (prefix, home);
72   
73   /* If `~/', remove any trailing / or replace leading // in $HOME.
74      Should really check for doubled intermediate slashes, too.  */
75   } else if (IS_DIR_SEP (name[1])) {
76     unsigned c = 1;
77     home = getenv (HOMEVAR);
78     if (!home) {
79       home = ".";
80     }
81     if (IS_DIR_SEP (*home) && IS_DIR_SEP (home[1])) {  /* handle leading // */
82       home++;
83     }
84     if (IS_DIR_SEP (home[strlen (home) - 1])) {        /* omit / after ~ */
85       c++;
86     }
87     expansion = concat3 (prefix, home, name + c);
88   
89   /* If `~user' or `~user/', look up user in the passwd database (but
90      OS/2 doesn't have this concept.  */
91   } else {
92 #ifdef HAVE_PWD_H
93       struct passwd *p;
94       string user;
95       unsigned c = 2;
96       while (!IS_DIR_SEP (name[c]) && name[c] != 0) /* find user name */
97         c++;
98       
99       user = (string) xmalloc (c);
100       strncpy (user, name + 1, c - 1);
101       user[c - 1] = 0;
102       
103       /* We only need the cast here for (deficient) systems
104          which do not declare `getpwnam' in <pwd.h>.  */
105       p = (struct passwd *) getpwnam (user);
106       free (user);
107
108       /* If no such user, just use `.'.  */
109       home = p ? p->pw_dir : ".";
110       if (IS_DIR_SEP (*home) && IS_DIR_SEP (home[1])) { /* handle leading // */
111         home++;
112       }
113       if (IS_DIR_SEP (home[strlen (home) - 1]) && name[c] != 0)
114         c++; /* If HOME ends in /, omit the / after ~user. */
115
116       expansion = concat3 (prefix, home, name + c);
117 #else /* not HAVE_PWD_H */
118       /* Since we don't know how to look up a user name, just return the
119          original string. */
120       if (*prefix)
121         name -= 2;
122       expansion = name;
123 #endif /* not HAVE_PWD_H */
124   }
125   /* We may return the same thing as the original, and then we might not
126      be returning a malloc-ed string.  Callers beware.  Sorry.  */
127   return (string) expansion;
128 }
129 \f
130 #ifdef TEST
131
132 void
133 test_expand_tilde (const_string filename)
134 {
135   string answer;
136   
137   printf ("Tilde expansion of `%s':\t", filename ? filename : "(nil)");
138   answer = kpse_tilde_expand (filename);
139   puts (answer);
140 }
141
142 int
143 main ()
144 {
145   string tilde_path = "tilde";
146
147   test_expand_tilde ("");
148   test_expand_tilde ("none");
149   test_expand_tilde ("~root");
150   test_expand_tilde ("~");
151   test_expand_tilde ("foo~bar");
152
153   test_expand_tilde ("!!");
154   test_expand_tilde ("!!none");
155   test_expand_tilde ("!!~root");
156   test_expand_tilde ("!!~");
157   test_expand_tilde ("!!foo~bar");
158   
159   return 0;
160 }
161
162 #endif /* TEST */
163
164 \f
165 /*
166 Local variables:
167 standalone-compile-command: "gcc -g -I. -I.. -DTEST tilde.c kpathsea.a"
168 End:
169 */