xref: /freebsd/contrib/tcsh/ma.setp.c (revision f7c32ed617858bcd22f8d1b03199099d50125721)
1 /*
2  * Copyright (c) 1990 Carnegie Mellon University
3  * All Rights Reserved.
4  *
5  * Permission to use, copy, modify and distribute this software and its
6  * documentation is hereby granted, provided that both the copyright
7  * notice and this permission notice appear in all copies of the
8  * software, derivative works or modified versions, and any portions
9  * thereof, and that both notices appear in supporting documentation.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND CARNEGIE MELLON UNIVERSITY
12  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
13  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT
14  * SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY SPECIAL, DIRECT,
15  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
16  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
17  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  *
20  * Users of this software agree to return to Carnegie Mellon any
21  * improvements or extensions that they make and grant Carnegie the
22  * rights to redistribute these changes.
23  *
24  * Export of this software is permitted only after complying with the
25  * regulations of the U.S. Deptartment of Commerce relating to the
26  * Export of Technical Data.
27  */
28 /*
29  *  setpath --- smart interface for setting path variables
30  *
31  *  usage:	setpath(paths, cmds, localsyspath, dosuffix, printerrors)
32  *		char **paths, **cmds, *localsyspath;
33  *		int dosuffix, printerrors;
34  *
35  *  The 'paths' argument is a list of pointers to path lists of the
36  *  form "name=value" where name is the name of the path and value
37  *  is a colon separated list of directories.  There can never be
38  *  more than MAXDIRS (64) directories in a path.
39  *
40  *  The 'cmds' argument may be a sequence of any of the following:
41  *	-r			reset path to default
42  *	-i newpath		insert newpath before localsyspath
43  *	-ia oldpath newpath	insert newpath after oldpath
44  *	-ib oldpath newpath	insert newpath before oldpath
45  *	-i# newpath		insert newpath at position #
46  *	-d oldpath		delete oldpath
47  *	-d#			delete path at position #
48  *	-c oldpath newpath	change oldpath to newpath
49  *	-c# newpath		change position # to newpath
50  *
51  *  The "-i newpath" command is equivilent to "-ib 'localsyspath' newpath".
52  *
53  *  If 'dosuffix' is true, the appropriate suffix will be added to
54  *  all command operands for any system path in 'paths'.
55  *
56  *  Both of the 'paths' and 'cmds' lists are terminated by a NULL
57  *  entry.
58  *
59  *  if 'printerrors' is true, setpath will printf error diagnostics.
60  *
61  *  WARNING !!!: Under no circumstances should anyone change this
62  *  module without fully understanding the impact on the C shell.
63  *  The C shell has it's own malloc and printf routines and this
64  *  module was carefully written taking that into account.  Do not
65  *  use any stdio routines from this module except printf.
66  *
67  **********************************************************************
68  * HISTORY
69  *
70  * Revision 1.4  90/12/11  17:58:44  mja
71  * 	Add copyright/disclaimer for distribution.
72  *
73  * 05-Jun-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
74  *	Make all non-entry points static.
75  *
76  * 30-Apr-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
77  *	Added -r switch to reset paths to their default values.
78  *
79  * 06-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
80  *	Created from old setpath program for the shell.
81  *
82  **********************************************************************
83  */
84 #include "sh.h"
85 
86 #ifdef MACH
87 
88 #define MAXDIRS 64		/* max directories on a path */
89 #ifndef NULL
90 # define NULL 0
91 #endif
92 
93 static int npaths;		/* # pathlist arguments */
94 
95 static struct pelem {
96     struct pelem *pnext;	/* pointer to next path */
97     char *pname;		/* name of pathlist */
98     char *psuf;			/* suffix for pathlist */
99     char *pdef;			/* default for pathlist */
100     int pdirs;			/* # directories on each pathlist */
101     char *pdir[MAXDIRS];	/* directory names for each pathlist */
102 } *pathhead = NULL;
103 
104 static struct {
105     char *name;
106     char *suffix;
107     char *defalt;
108 } syspath[] = {
109     "PATH",	"/bin",		":/usr/ucb:/bin:/usr/bin",
110     "CPATH",	"/include",	":/usr/include",
111     "LPATH",	"/lib",		":/lib:/usr/lib",
112     "MPATH",	"/man",		":/usr/man",
113     "EPATH",	"/maclib",	"",
114     0, 0, 0
115 };
116 
117 static int sflag;
118 static int eflag;
119 
120 #define INVALID { \
121 	if (eflag) xprintf(CGETS(10, 1, \
122 				 "setpath: invalid command '%s'.\n"), cmd); \
123 	freepaths(); \
124 	return(-1); \
125 }
126 
127 #define TOOFEW { \
128 	if (eflag) xprintf(CGETS(10, 2, \
129 		 "setpath: insufficient arguments to command '%s'.\n"), cmd); \
130 	freepaths(); \
131 	return(-1); \
132 }
133 
134 static int initpaths	(char **);
135 static void savepaths	(char **);
136 static void freepaths	(void);
137 static void tcsh_rcmd	(char *);
138 static void icmd	(char *, char *);
139 static void iacmd	(char *, char *);
140 static void ibcmd	(char *, char *);
141 static void incmd	(char *, int);
142 static void insert	(struct pelem *, int, char *);
143 static void dcmd	(char *);
144 static void dncmd	(int);
145 static void delete	(struct pelem *, int);
146 static void ccmd	(char *, char *);
147 static void cncmd	(char *, int);
148 static void change	(struct pelem *, int, char *);
149 static int locate	(struct pelem *, char *);
150 
151 
152 
153 int
154 setpath(char **paths, char **cmds, char *localsyspath, int dosuffix,
155 	int printerrors)
156 {
157     char *cmd, *cmd1, *cmd2;
158     int ncmd;
159 
160     sflag = dosuffix;
161     eflag = printerrors;
162     if (initpaths(paths) < 0)
163 	return(-1);
164     if (npaths == 0)
165 	return(0);
166     for (ncmd = 0; cmd = cmds[ncmd]; ncmd++) {
167 	if (cmd[0] != '-')
168 	    INVALID;
169 	cmd1 = cmds[ncmd+1];
170 	cmd2 = cmds[ncmd+2];
171 	switch (cmd[1]) {
172 	case 'r':
173 	    if (cmd[2] != '\0')
174 		INVALID;
175 	    tcsh_rcmd(localsyspath);
176 	    break;
177 	case 'i':
178 	    if (cmd[2] == '\0') {
179 		ncmd++;
180 		if (cmd1 == NULL) TOOFEW;
181 		icmd(cmd1, localsyspath);
182 	    } else if (isdigit(cmd[2])) {
183 		ncmd++;
184 		if (cmd1 == NULL) TOOFEW;
185 		incmd(cmd1, atoi(cmd+2));
186 	    } else if (cmd[3] != '\0' || (cmd[2] != 'a' && cmd[2] != 'b')) {
187 		INVALID;
188 	    } else {
189 		ncmd += 2;
190 		if (cmd1 == NULL || cmd2 == NULL) TOOFEW;
191 		if (cmd[2] == 'a')
192 		    iacmd(cmd1, cmd2);
193 		else
194 		    ibcmd(cmd1, cmd2);
195 	    }
196 	    break;
197 	case 'd':
198 	    if (cmd[2] == '\0') {
199 		ncmd++;
200 		if (cmd1 == NULL) TOOFEW;
201 		dcmd(cmd1);
202 	    } else if (isdigit(cmd[2]))
203 		dncmd(atoi(cmd+2));
204 	    else {
205 		INVALID;
206 	    }
207 	    break;
208 	case 'c':
209 	    if (cmd[2] == '\0') {
210 		ncmd += 2;
211 		if (cmd1 == NULL || cmd2 == NULL) TOOFEW;
212 		ccmd(cmd1, cmd2);
213 	    } else if (isdigit(cmd[2])) {
214 		ncmd++;
215 		if (cmd1 == NULL) TOOFEW;
216 		cncmd(cmd1, atoi(cmd+2));
217 	    } else {
218 		INVALID;
219 	    }
220 	    break;
221 	default:
222 	    INVALID;
223 	}
224     }
225     savepaths(paths);
226     freepaths();
227     return(0);
228 }
229 
230 static int
231 initpaths(char **paths)
232 {
233     char *path, *val, *p, *q;
234     int i, done;
235     struct pelem *pe, *pathend;
236 
237     freepaths();
238     for (npaths = 0; path = paths[npaths]; npaths++) {
239 	val = index(path, '=');
240 	if (val == NULL) {
241 	    if (eflag)
242 		xprintf(CGETS(10, 3,
243 			      "setpath: value missing in path '%s'\n"), path);
244 	    freepaths();
245 	    return(-1);
246 	}
247 	*val++ = '\0';
248 	pe = xmalloc(sizeof(struct pelem));
249 	setzero(pe, sizeof(struct pelem));
250 	if (pathhead == NULL)
251 	    pathhead = pathend = pe;
252 	else {
253 	    pathend->pnext = pe;
254 	    pathend = pe;
255 	}
256 	p = strsave(path);
257 	pe->pname = p;
258 	pe->psuf = "";
259 	pe->pdef = "";
260 	for (i = 0; syspath[i].name; i++)
261 	    if (strcmp(pe->pname, syspath[i].name) == 0) {
262 		pe->psuf = syspath[i].suffix;
263 		pe->pdef = syspath[i].defalt;
264 		break;
265 	    }
266 	q = val;
267 	for (;;) {
268 	    q = index(p = q, ':');
269 	    done = (q == NULL);
270 	    if (!done)
271 		*q++ = '\0';
272 	    p = strsave(p);
273 	    pe->pdir[pe->pdirs] = p;
274 	    pe->pdirs++;
275 	    if (done)
276 		break;
277 	}
278     }
279     return(0);
280 }
281 
282 static void
283 savepaths(char **paths)
284 {
285     char *p, *q;
286     int npath, i, len;
287     struct pelem *pe;
288 
289     for (npath = 0, pe = pathhead; pe; npath++, pe = pe->pnext) {
290 	len = strlen(pe->pname) + 1;
291 	if (pe->pdirs == 0)
292 	    len++;
293 	else for (i = 0; i < pe->pdirs; i++)
294 	    len += strlen(pe->pdir[i]) + 1;
295 	p = xmalloc((unsigned)len);
296 	paths[npath] = p;
297 	for (q = pe->pname; *p = *q; p++, q++);
298 	*p++ = '=';
299 	if (pe->pdirs != 0) {
300 	    for (i = 0; i < pe->pdirs; i++) {
301 		for (q = pe->pdir[i]; *p = *q; p++, q++);
302 		*p++ = ':';
303 	    }
304 	    p--;
305 	}
306 	*p = '\0';
307     }
308 }
309 
310 static void
311 freepaths(void)
312 {
313     char *p;
314     int i;
315     struct pelem *pe;
316 
317     if (npaths == 0 || pathhead == NULL)
318 	return;
319     while (pe = pathhead) {
320 	if (pe->pname) {
321 	    for (i = 0; i < pe->pdirs; i++) {
322 		if (pe->pdir[i] == NULL)
323 		    continue;
324 		p = pe->pdir[i];
325 		pe->pdir[i] = NULL;
326 		xfree((ptr_t) p);
327 	    }
328 	    pe->pdirs = 0;
329 	    p = pe->pname;
330 	    pe->pname = NULL;
331 	    xfree((ptr_t) p);
332 	}
333 	pathhead = pe->pnext;
334 	xfree((ptr_t) pe);
335     }
336     npaths = 0;
337 }
338 
339 /***********************************************
340  ***    R E S E T   A   P A T H N A M E    ***
341  ***********************************************/
342 
343 static void
344 tcsh_rcmd(char *localsyspath)	/* reset path with localsyspath */
345 {
346     int n, done;
347     char *new, *p;
348     struct pelem *pe;
349     char newbuf[MAXPATHLEN+1];/*FIXBUF*/
350 
351     for (pe = pathhead; pe; pe = pe->pnext) {
352 	new = newbuf;
353 	*new = '\0';
354 	if (localsyspath != NULL) {
355 	    *new = ':';
356 	    (void) strcpy(new + 1, localsyspath);
357 	    (void) strcat(new, pe->psuf);
358 	}
359 	(void) strcat(new, pe->pdef);
360 	for (n = 0; n < pe->pdirs; n++) {
361 	    if (pe->pdir[n] == NULL)
362 		continue;
363 	    p = pe->pdir[n];
364 	    pe->pdir[n] = NULL;
365 	    xfree((ptr_t) p);
366 	}
367 	pe->pdirs = 0;
368 	for (;;) {
369 	    new = index(p = new, ':');
370 	    done = (new == NULL);
371 	    if (!done)
372 		*new++ = '\0';
373 	    p = strsave(p);
374 	    pe->pdir[pe->pdirs] = p;
375 	    pe->pdirs++;
376 	    if (done)
377 		break;
378 	}
379     }
380 }
381 
382 /***********************************************
383  ***    I N S E R T   A   P A T H N A M E    ***
384  ***********************************************/
385 
386 static void
387 icmd(char *path, char *localsyspath)	/* insert path before localsyspath */
388 {
389     int n;
390     char *new;
391     struct pelem *pe;
392     char newbuf[MAXPATHLEN+1];/*FIXBUF*/
393 
394     for (pe = pathhead; pe; pe = pe->pnext) {
395 	if (sflag)
396 	    new = localsyspath;
397 	else {
398 	    new = newbuf;
399 	    (void) strcpy(new, localsyspath);
400 	    (void) strcat(new, pe->psuf);
401 	}
402 	n = locate(pe, new);
403 	if (n >= 0)
404 	    insert(pe, n, path);
405 	else
406 	    insert(pe, 0, path);
407     }
408 }
409 
410 static void
411 iacmd(char *inpath, char *path)	/* insert path after inpath */
412 {
413     int n;
414     struct pelem *pe;
415 
416     for (pe = pathhead; pe; pe = pe->pnext) {
417 	n = locate(pe, inpath);
418 	if (n >= 0)
419 	    insert(pe, n + 1, path);
420 	else
421 	    xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
422 		    inpath, pe->pname);
423     }
424 }
425 
426 static void
427 ibcmd(char *inpath, char *path)	/* insert path before inpath */
428 {
429     int n;
430     struct pelem *pe;
431 
432     for (pe = pathhead; pe; pe = pe->pnext) {
433 	n = locate(pe, inpath);
434 	if (n >= 0)
435 	    insert(pe, n, path);
436 	else
437 	    xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
438 		    inpath, pe->pname);
439     }
440 }
441 
442 static void
443 incmd(char *path, int n)	/* insert path at position n */
444 {
445     struct pelem *pe;
446 
447     for (pe = pathhead; pe; pe = pe->pnext)
448 	insert(pe, n, path);
449 }
450 
451 static void
452 insert(struct pelem *pe, int loc, char *key)
453 {
454     int i;
455     char *new;
456     char newbuf[2000];/*FIXBUF*/
457 
458     if (sflag) {		/* add suffix */
459 	new = newbuf;
460 	(void) strcpy(new, key);
461 	(void) strcat(new, pe->psuf);
462     } else
463 	new = key;
464     new = strsave(new);
465     for (i = pe->pdirs; i > loc; --i)
466 	pe->pdir[i] = pe->pdir[i-1];
467     if (loc > pe->pdirs)
468 	loc = pe->pdirs;
469     pe->pdir[loc] = new;
470     pe->pdirs++;
471 }
472 
473 /***********************************************
474  ***    D E L E T E   A   P A T H N A M E    ***
475  ***********************************************/
476 
477 static void
478 dcmd(char *path)		/* delete path */
479 {
480     int n;
481     struct pelem *pe;
482 
483     for (pe = pathhead; pe; pe = pe->pnext) {
484 	n = locate(pe, path);
485 	if (n >= 0)
486 	    delete(pe, n);
487 	else
488 	    xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
489 		    path, pe->pname);
490     }
491 }
492 
493 static void
494 dncmd(int n)			/* delete at position n */
495 {
496     struct pelem *pe;
497 
498     for (pe = pathhead; pe; pe = pe->pnext) {
499 	if (n < pe->pdirs)
500 	    delete(pe, n);
501 	else
502 	    xprintf(CGETS(10, 5,
503 			    "setpath: %d not valid position in %s\n"),
504 		    n, pe->pname);
505     }
506 }
507 
508 static void
509 delete(struct pelem *pe, int n)
510 {
511     int d;
512 
513     xfree((ptr_t) (pe->pdir[n]));
514     for (d = n; d < pe->pdirs - 1; d++)
515 	pe->pdir[d] = pe->pdir[d+1];
516     --pe->pdirs;
517 }
518 
519 /***********************************************
520  ***    C H A N G E   A   P A T H N A M E    ***
521  ***********************************************/
522 
523 static void
524 ccmd(char *inpath, char *path)	/* change inpath to path */
525 {
526     int n;
527     struct pelem *pe;
528 
529     for (pe = pathhead; pe; pe = pe->pnext) {
530 	n = locate(pe, inpath);
531 	if (n >= 0)
532 	    change(pe, n, path);
533 	else
534 	    xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
535 		    inpath, pe->pname);
536     }
537 }
538 
539 static void
540 cncmd(char *path, int n)	/* change at position n to path */
541 {
542     struct pelem *pe;
543 
544     for (pe = pathhead; pe; pe = pe->pnext) {
545 	if (n < pe->pdirs)
546 	    change(pe, n, path);
547 	else
548 	    xprintf(CGETS(10, 5,
549 			    "setpath: %d not valid position in %s\n"),
550 		    n, pe->pname);
551     }
552 }
553 
554 static void
555 change(struct pelem *pe, int loc, char *key)
556 {
557     char *new;
558     char newbuf[MAXPATHLEN+1];/*FIXBUF*/
559 
560     if (sflag) {		/* append suffix */
561 	new = newbuf;
562 	(void) strcpy(new, key);
563 	(void) strcat(new, pe->psuf);
564     } else
565 	new = key;
566     new = strsave(new);
567     xfree((ptr_t) (pe->pdir[loc]));
568     pe->pdir[loc] = new;
569 }
570 
571 /***************************************
572  ***    F I N D   P A T H N A M E    ***
573  ***************************************/
574 
575 static int
576 locate(struct pelem *pe, char *key)
577 {
578     int i;
579     char *realkey;
580     char keybuf[MAXPATHLEN+1];/*FIXBUF*/
581 
582     if (sflag) {
583 	realkey = keybuf;
584 	(void) strcpy(realkey, key);
585 	(void) strcat(realkey, pe->psuf);
586     } else
587 	realkey = key;
588     for (i = 0; i < pe->pdirs; i++)
589 	if (strcmp(pe->pdir[i], realkey) == 0)
590 	    break;
591     return((i < pe->pdirs) ? i : -1);
592 }
593 #endif
594