make install of mv a special case
[unix-history] / usr / src / bin / csh / dir.c
CommitLineData
106427f7
BJ
1static char *sccsid = "@(#)dir.c 4.1 %G%";
2
3#include "sh.h"
4#include "sh.dir.h"
5
6/*
7 * C Shell - directory management
8 */
9
10struct directory *dfind();
11char *dfollow();
12struct directory dhead; /* "head" of loop */
13int printd; /* force name to be printed */
14static char *fakev[] = { "dirs", NOSTR };
15
16/*
17 * dinit - initialize current working directory
18 */
19dinit(hp)
20 char *hp;
21{
22 register char *cp;
23 register struct directory *dp;
24 char path[BUFSIZ];
25
26 if (loginsh && hp)
27 cp = hp;
28 else
29 cp = getwd(path);
30 dp = (struct directory *)calloc(sizeof (struct directory), 1);
31 dp->di_name = savestr(cp);
32 dp->di_count = 0;
33 dhead.di_next = dhead.di_prev = dp;
34 dp->di_next = dp->di_prev = &dhead;
35 printd = 0;
36 dnewcwd(dp);
37}
38
39/*
40 * dodirs - list all directories in directory loop
41 */
42dodirs(v)
43 char **v;
44{
45 register struct directory *dp;
46 bool lflag;
47 char *hp = value("home");
48
49 if (*hp == '\0')
50 hp = NOSTR;
51 if (*++v != NOSTR)
52 if (eq(*v, "-l") && *++v == NOSTR)
53 lflag = 1;
54 else
55 error("Usage: dirs [ -l ]");
56 else
57 lflag = 0;
58 dp = dcwd;
59 do {
60 if (dp == &dhead)
61 continue;
62 if (!lflag && hp != NOSTR) {
63 dtildepr(hp, dp->di_name);
64 } else
65 printf("%s", dp->di_name);
66 printf(" ");
67 } while ((dp = dp->di_prev) != dcwd);
68 printf("\n");
69}
70
71dtildepr(home, dir)
72 register char *home, *dir;
73{
74
75 if (!eq(home, "/") && prefix(home, dir))
76 printf("~%s", dir + strlen(home));
77 else
78 printf("%s", dir);
79}
80
81/*
82 * dochngd - implement chdir command.
83 */
84dochngd(v)
85 char **v;
86{
87 register char *cp;
88 register struct directory *dp;
89
90 printd = 0;
91 if (*++v == NOSTR) {
92 if ((cp = value("home")) == NOSTR || *cp == 0)
93 bferr("No home directory");
94 if (chdir(cp) < 0)
95 bferr("Can't change to home directory");
96 cp = savestr(cp);
97 } else if ((dp = dfind(*v)) != 0) {
98 printd = 1;
99 if (chdir(dp->di_name) < 0)
100 Perror(dp->di_name);
101 dcwd->di_prev->di_next = dcwd->di_next;
102 dcwd->di_next->di_prev = dcwd->di_prev;
103 goto flushcwd;
104 } else
105 cp = dfollow(*v);
106 dp = (struct directory *)calloc(sizeof (struct directory), 1);
107 dp->di_name = cp;
108 dp->di_count = 0;
109 dp->di_next = dcwd->di_next;
110 dp->di_prev = dcwd->di_prev;
111 dp->di_prev->di_next = dp;
112 dp->di_next->di_prev = dp;
113flushcwd:
114 dfree(dcwd);
115 dnewcwd(dp);
116}
117
118/*
119 * dfollow - change to arg directory; fall back on cdpath if not valid
120 */
121char *
122dfollow(cp)
123 register char *cp;
124{
125 register char **cdp;
126 struct varent *c;
127
128 cp = globone(cp);
129 if (chdir(cp) == 0)
130 goto gotcha;
131 if (cp[0] != '/' && !prefix("./", cp) && !prefix("../", cp)
132 && (c = adrof("cdpath"))) {
133 for (cdp = c->vec; *cdp; cdp++) {
134 char buf[BUFSIZ];
135
136 strcpy(buf, *cdp);
137 strcat(buf, "/");
138 strcat(buf, cp);
139 if (chdir(buf) >= 0) {
140 printd = 1;
141 xfree(cp);
142 cp = savestr(buf);
143 goto gotcha;
144 }
145 }
146 }
147 if (adrof(cp)) {
148 char *dp = value(cp);
149
150 if (dp[0] == '/' || dp[0] == '.')
151 if (chdir(dp) >= 0) {
152 xfree(cp);
153 cp = savestr(dp);
154 printd = 1;
155 goto gotcha;
156 }
157 }
158 xfree(cp);
159 Perror(cp);
160
161gotcha:
162 if (*cp != '/') {
163 char *dp = calloc(strlen(cp) + strlen(dcwd->di_name) + 2, 1);
164 strcpy(dp, dcwd->di_name);
165 strcat(dp, "/");
166 strcat(dp, cp);
167 xfree(cp);
168 cp = dp;
169 }
170 dcanon(cp);
171 return (cp);
172}
173
174/*
175 * dopushd - push new directory onto directory stack.
176 * with no arguments exchange top and second.
177 * with numeric argument (+n) bring it to top.
178 */
179dopushd(v)
180 char **v;
181{
182 register struct directory *dp;
183
184 printd = 1;
185 if (*++v == NOSTR) {
186 if ((dp = dcwd->di_prev) == &dhead)
187 dp = dhead.di_prev;
188 if (dp == dcwd)
189 bferr("No other directory");
190 if (chdir(dp->di_name) < 0)
191 Perror(dp->di_name);
192 dp->di_prev->di_next = dp->di_next;
193 dp->di_next->di_prev = dp->di_prev;
194 dp->di_next = dcwd->di_next;
195 dp->di_prev = dcwd;
196 dcwd->di_next->di_prev = dp;
197 dcwd->di_next = dp;
198 } else if (dp = dfind(*v)) {
199 if (chdir(dp->di_name) < 0)
200 Perror(dp->di_name);
201 } else {
202 register char *cp;
203
204 cp = dfollow(*v);
205 dp = (struct directory *)calloc(sizeof (struct directory), 1);
206 dp->di_name = cp;
207 dp->di_count = 0;
208 dp->di_prev = dcwd;
209 dp->di_next = dcwd->di_next;
210 dcwd->di_next = dp;
211 dp->di_next->di_prev = dp;
212 }
213 dnewcwd(dp);
214}
215
216/*
217 * dfind - find a directory if specified by numeric (+n) argument
218 */
219struct directory *
220dfind(cp)
221 register char *cp;
222{
223 register struct directory *dp;
224 register int i;
225 register char *ep;
226
227 if (*cp++ != '+')
228 return (0);
229 for (ep = cp; digit(*ep); ep++)
230 continue;
231 if (*ep)
232 return (0);
233 i = getn(cp);
234 if (i <= 0)
235 return (0);
236 for (dp = dcwd; i != 0; i--) {
237 if ((dp = dp->di_prev) == &dhead)
238 dp = dp->di_prev;
239 if (dp == dcwd)
240 bferr("Directory stack not that deep");
241 }
242 return (dp);
243}
244
245/*
246 * dopopd - pop a directory out of the directory stack
247 * with a numeric argument just discard it.
248 */
249dopopd(v)
250 char **v;
251{
252 register struct directory *dp, *p;
253
254 printd = 1;
255 if (*++v == NOSTR)
256 dp = dcwd;
257 else if ((dp = dfind(*v)) == 0)
258 bferr("Bad directory");
259 if (dp->di_prev == &dhead && dp->di_next == &dhead)
260 bferr("Directory stack empty");
261 if (dp == dcwd) {
262 if ((p = dp->di_prev) == &dhead)
263 p = dhead.di_prev;
264 if (chdir(p->di_name) < 0)
265 Perror(p->di_name);
266 }
267 dp->di_prev->di_next = dp->di_next;
268 dp->di_next->di_prev = dp->di_prev;
269 if (dp == dcwd)
270 dnewcwd(p);
271 else
272 dodirs(fakev);
273 dfree(dp);
274}
275
276/*
277 * dfree - free the directory (or keep it if it still has ref count)
278 */
279dfree(dp)
280 register struct directory *dp;
281{
282
283 if (dp->di_count != 0)
284 dp->di_next = dp->di_prev = 0;
285 else
286 xfree(dp->di_name), xfree((char *)dp);
287}
288
289/*
290 * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
291 * we are of course assuming that the file system is standardly
292 * constructed (always have ..'s, directories have links)
293 */
294dcanon(cp)
295 char *cp;
296{
297 register char *p, *sp;
298 register bool slash;
299
300 if (*cp != '/')
301 abort();
302 for (p = cp; *p; ) { /* for each component */
303 sp = p; /* save slash address */
304 while(*++p == '/') /* flush extra slashes */
305 ;
306 if (p != ++sp)
307 strcpy(sp, p);
308 p = sp; /* save start of component */
309 slash = 0;
310 while(*++p) /* find next slash or end of path */
311 if (*p == '/') {
312 slash = 1;
313 *p = 0;
314 break;
315 }
316 if (*sp == '\0') /* if component is null */
317 if (--sp == cp) /* if path is one char (i.e. /) */
318 break;
319 else
320 *sp = '\0';
321 else if (eq(".", sp)) {
322 if (slash) {
323 strcpy(sp, ++p);
324 p = --sp;
325 } else if (--sp != cp)
326 *sp = '\0';
327 } else if (eq("..", sp)) {
328 if (--sp != cp)
329 while (*--sp != '/')
330 ;
331 if (slash) {
332 strcpy(++sp, ++p);
333 p = --sp;
334 } else if (cp == sp)
335 *++sp = '\0';
336 else
337 *sp = '\0';
338 } else if (slash)
339 *p = '/';
340 }
341}
342
343/*
344 * dnewcwd - make a new directory in the loop the current one
345 */
346dnewcwd(dp)
347 register struct directory *dp;
348{
349
350 dcwd = dp;
351 set("cwd", savestr(dcwd->di_name));
352 if (printd)
353 dodirs(fakev);
354}