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