|
|
1.1 root 1: static char *sccsid = "@(#)sh.dir.c 4.2 2/3/83";
2:
3: #include "sh.h"
4: #include "sh.dir.h"
5:
6: /*
7: * C Shell - directory management
8: */
9:
10: struct directory *dfind();
11: char *dfollow();
12: struct directory dhead; /* "head" of loop */
13: int printd; /* force name to be printed */
14: static char *fakev[] = { "dirs", NOSTR };
15:
16: /*
17: * dinit - initialize current working directory
18: */
19: dinit(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: if (cp == NULL) {
31: write(2, path, strlen(path));
32: exit(1);
33: }
34: }
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: */
47: dodirs(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:
76: dtildepr(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: */
89: dochngd(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;
118: flushcwd:
119: dfree(dcwd);
120: dnewcwd(dp);
121: }
122:
123: /*
124: * dfollow - change to arg directory; fall back on cdpath if not valid
125: */
126: char *
127: dfollow(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:
166: gotcha:
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: */
184: dopushd(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: */
224: struct directory *
225: dfind(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: */
254: dopopd(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: */
284: dfree(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: */
299: dcanon(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: */
351: dnewcwd(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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.