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