xref: /freebsd/contrib/tcsh/ma.setp.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
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 RCSID("$Id: ma.setp.c,v 1.12 1996/04/26 19:18:36 christos Exp $")
86 
87 #ifdef MACH
88 
89 #define MAXDIRS 64		/* max directories on a path */
90 #ifndef NULL
91 # define NULL 0
92 #endif
93 
94 static int npaths;		/* # pathlist arguments */
95 
96 static struct pelem {
97     struct pelem *pnext;	/* pointer to next path */
98     char *pname;		/* name of pathlist */
99     char *psuf;			/* suffix for pathlist */
100     char *pdef;			/* default for pathlist */
101     int pdirs;			/* # directories on each pathlist */
102     char *pdir[MAXDIRS];	/* directory names for each pathlist */
103 } *pathhead = NULL;
104 
105 static struct {
106     char *name;
107     char *suffix;
108     char *defalt;
109 } syspath[] = {
110     "PATH",	"/bin",		":/usr/ucb:/bin:/usr/bin",
111     "CPATH",	"/include",	":/usr/include",
112     "LPATH",	"/lib",		":/lib:/usr/lib",
113     "MPATH",	"/man",		":/usr/man",
114     "EPATH",	"/maclib",	"",
115     0, 0, 0
116 };
117 
118 static int sflag;
119 static int eflag;
120 
121 #define INVALID { \
122 	if (eflag) xprintf(CGETS(10, 1, \
123 				 "setpath: invalid command '%s'.\n"), cmd); \
124 	freepaths(); \
125 	return(-1); \
126 }
127 
128 #define TOOFEW { \
129 	if (eflag) xprintf(CGETS(10, 2, \
130 		 "setpath: insufficient arguments to command '%s'.\n"), cmd); \
131 	freepaths(); \
132 	return(-1); \
133 }
134 
135 static int initpaths	__P((char **));
136 static void savepaths	__P((char **));
137 static void freepaths	__P((void));
138 static void rcmd	__P((char *));
139 static void icmd	__P((char *, char *));
140 static void iacmd	__P((char *, char *));
141 static void ibcmd	__P((char *, char *));
142 static void incmd	__P((char *, int));
143 static void insert	__P((struct pelem *, int, char *));
144 static void dcmd	__P((char *));
145 static void dncmd	__P((int));
146 static void delete	__P((struct pelem *, int));
147 static void ccmd	__P((char *, char *));
148 static void cncmd	__P((char *, int));
149 static void change	__P((struct pelem *, int, char *));
150 static int locate	__P((struct pelem *, char *));
151 
152 
153 
154 int
155 setpath(paths, cmds, localsyspath, dosuffix, printerrors)
156 register char **paths, **cmds, *localsyspath;
157 int dosuffix, printerrors;
158 {
159     register char *cmd, *cmd1, *cmd2;
160     register int ncmd;
161 
162     sflag = dosuffix;
163     eflag = printerrors;
164     if (initpaths(paths) < 0)
165 	return(-1);
166     if (npaths == 0)
167 	return(0);
168     for (ncmd = 0; cmd = cmds[ncmd]; ncmd++) {
169 	if (cmd[0] != '-')
170 	    INVALID;
171 	cmd1 = cmds[ncmd+1];
172 	cmd2 = cmds[ncmd+2];
173 	switch (cmd[1]) {
174 	case 'r':
175 	    if (cmd[2] != '\0')
176 		INVALID;
177 	    rcmd(localsyspath);
178 	    break;
179 	case 'i':
180 	    if (cmd[2] == '\0') {
181 		ncmd++;
182 		if (cmd1 == NULL) TOOFEW;
183 		icmd(cmd1, localsyspath);
184 	    } else if (isdigit(cmd[2])) {
185 		ncmd++;
186 		if (cmd1 == NULL) TOOFEW;
187 		incmd(cmd1, atoi(cmd+2));
188 	    } else if (cmd[3] != '\0' || (cmd[2] != 'a' && cmd[2] != 'b')) {
189 		INVALID;
190 	    } else {
191 		ncmd += 2;
192 		if (cmd1 == NULL || cmd2 == NULL) TOOFEW;
193 		if (cmd[2] == 'a')
194 		    iacmd(cmd1, cmd2);
195 		else
196 		    ibcmd(cmd1, cmd2);
197 	    }
198 	    break;
199 	case 'd':
200 	    if (cmd[2] == '\0') {
201 		ncmd++;
202 		if (cmd1 == NULL) TOOFEW;
203 		dcmd(cmd1);
204 	    } else if (isdigit(cmd[2]))
205 		dncmd(atoi(cmd+2));
206 	    else {
207 		INVALID;
208 	    }
209 	    break;
210 	case 'c':
211 	    if (cmd[2] == '\0') {
212 		ncmd += 2;
213 		if (cmd1 == NULL || cmd2 == NULL) TOOFEW;
214 		ccmd(cmd1, cmd2);
215 	    } else if (isdigit(cmd[2])) {
216 		ncmd++;
217 		if (cmd1 == NULL) TOOFEW;
218 		cncmd(cmd1, atoi(cmd+2));
219 	    } else {
220 		INVALID;
221 	    }
222 	    break;
223 	default:
224 	    INVALID;
225 	}
226     }
227     savepaths(paths);
228     freepaths();
229     return(0);
230 }
231 
232 static int
233 initpaths(paths)
234 register char **paths;
235 {
236     register char *path, *val, *p, *q;
237     register int i, done;
238     register struct pelem *pe, *pathend;
239 
240     freepaths();
241     for (npaths = 0; path = paths[npaths]; npaths++) {
242 	val = index(path, '=');
243 	if (val == NULL) {
244 	    if (eflag)
245 		xprintf(CGETS(10, 3,
246 			      "setpath: value missing in path '%s'\n"), path);
247 	    freepaths();
248 	    return(-1);
249 	}
250 	*val++ = '\0';
251 	pe = (struct pelem *)xmalloc((unsigned)(sizeof(struct pelem)));
252 	setzero((char *) pe, sizeof(struct pelem));
253 	if (pathhead == NULL)
254 	    pathhead = pathend = pe;
255 	else {
256 	    pathend->pnext = pe;
257 	    pathend = pe;
258 	}
259 	p = strsave(path);
260 	pe->pname = p;
261 	pe->psuf = "";
262 	pe->pdef = "";
263 	for (i = 0; syspath[i].name; i++)
264 	    if (strcmp(pe->pname, syspath[i].name) == 0) {
265 		pe->psuf = syspath[i].suffix;
266 		pe->pdef = syspath[i].defalt;
267 		break;
268 	    }
269 	q = val;
270 	for (;;) {
271 	    q = index(p = q, ':');
272 	    done = (q == NULL);
273 	    if (!done)
274 		*q++ = '\0';
275 	    p = strsave(p);
276 	    pe->pdir[pe->pdirs] = p;
277 	    pe->pdirs++;
278 	    if (done)
279 		break;
280 	}
281     }
282     return(0);
283 }
284 
285 static void
286 savepaths(paths)
287 register char **paths;
288 {
289     register char *p, *q;
290     register int npath, i, len;
291     register struct pelem *pe;
292 
293     for (npath = 0, pe = pathhead; pe; npath++, pe = pe->pnext) {
294 	len = strlen(pe->pname) + 1;
295 	if (pe->pdirs == 0)
296 	    len++;
297 	else for (i = 0; i < pe->pdirs; i++)
298 	    len += strlen(pe->pdir[i]) + 1;
299 	p = xmalloc((unsigned)len);
300 	paths[npath] = p;
301 	for (q = pe->pname; *p = *q; p++, q++);
302 	*p++ = '=';
303 	if (pe->pdirs != 0) {
304 	    for (i = 0; i < pe->pdirs; i++) {
305 		for (q = pe->pdir[i]; *p = *q; p++, q++);
306 		*p++ = ':';
307 	    }
308 	    p--;
309 	}
310 	*p = '\0';
311     }
312 }
313 
314 static void
315 freepaths()
316 {
317     register char *p;
318     register int i;
319     register struct pelem *pe;
320 
321     if (npaths == 0 || pathhead == NULL)
322 	return;
323     while (pe = pathhead) {
324 	if (pe->pname) {
325 	    for (i = 0; i < pe->pdirs; i++) {
326 		if (pe->pdir[i] == NULL)
327 		    continue;
328 		p = pe->pdir[i];
329 		pe->pdir[i] = NULL;
330 		xfree((ptr_t) p);
331 	    }
332 	    pe->pdirs = 0;
333 	    p = pe->pname;
334 	    pe->pname = NULL;
335 	    xfree((ptr_t) p);
336 	}
337 	pathhead = pe->pnext;
338 	xfree((ptr_t) pe);
339     }
340     npaths = 0;
341 }
342 
343 /***********************************************
344  ***    R E S E T   A   P A T H N A M E    ***
345  ***********************************************/
346 
347 static void
348 rcmd(localsyspath)		/* reset path with localsyspath */
349 char *localsyspath;
350 {
351     register int n, done;
352     register char *new, *p;
353     register struct pelem *pe;
354     char newbuf[MAXPATHLEN+1];
355 
356     for (pe = pathhead; pe; pe = pe->pnext) {
357 	new = newbuf;
358 	*new = '\0';
359 	if (localsyspath != NULL) {
360 	    *new = ':';
361 	    (void) strcpy(new + 1, localsyspath);
362 	    (void) strcat(new, pe->psuf);
363 	}
364 	(void) strcat(new, pe->pdef);
365 	for (n = 0; n < pe->pdirs; n++) {
366 	    if (pe->pdir[n] == NULL)
367 		continue;
368 	    p = pe->pdir[n];
369 	    pe->pdir[n] = NULL;
370 	    xfree((ptr_t) p);
371 	}
372 	pe->pdirs = 0;
373 	for (;;) {
374 	    new = index(p = new, ':');
375 	    done = (new == NULL);
376 	    if (!done)
377 		*new++ = '\0';
378 	    p = strsave(p);
379 	    pe->pdir[pe->pdirs] = p;
380 	    pe->pdirs++;
381 	    if (done)
382 		break;
383 	}
384     }
385 }
386 
387 /***********************************************
388  ***    I N S E R T   A   P A T H N A M E    ***
389  ***********************************************/
390 
391 static void
392 icmd(path, localsyspath)	/* insert path before localsyspath */
393 char *path, *localsyspath;
394 {
395     register int n;
396     register char *new;
397     register struct pelem *pe;
398     char newbuf[MAXPATHLEN+1];
399 
400     for (pe = pathhead; pe; pe = pe->pnext) {
401 	if (sflag)
402 	    new = localsyspath;
403 	else {
404 	    new = newbuf;
405 	    (void) strcpy(new, localsyspath);
406 	    (void) strcat(new, pe->psuf);
407 	}
408 	n = locate(pe, new);
409 	if (n >= 0)
410 	    insert(pe, n, path);
411 	else
412 	    insert(pe, 0, path);
413     }
414 }
415 
416 static void
417 iacmd(inpath, path)		/* insert path after inpath */
418 char *inpath, *path;
419 {
420     register int n;
421     register struct pelem *pe;
422 
423     for (pe = pathhead; pe; pe = pe->pnext) {
424 	n = locate(pe, inpath);
425 	if (n >= 0)
426 	    insert(pe, n + 1, path);
427 	else
428 	    xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
429 		    inpath, pe->pname);
430     }
431 }
432 
433 static void
434 ibcmd(inpath, path)		/* insert path before inpath */
435 char *inpath, *path;
436 {
437     register int n;
438     register struct pelem *pe;
439 
440     for (pe = pathhead; pe; pe = pe->pnext) {
441 	n = locate(pe, inpath);
442 	if (n >= 0)
443 	    insert(pe, n, path);
444 	else
445 	    xprintf(CGETS(10, 4, "setpath: %s not found in %s\n",
446 		    inpath, pe->pname));
447     }
448 }
449 
450 static void
451 incmd(path, n)			/* insert path at position n */
452 char *path;
453 int n;
454 {
455     register struct pelem *pe;
456 
457     for (pe = pathhead; pe; pe = pe->pnext)
458 	insert(pe, n, path);
459 }
460 
461 static void
462 insert(pe, loc, key)
463 register struct pelem *pe;
464 register int loc;
465 register char *key;
466 {
467     register int i;
468     register char *new;
469     char newbuf[2000];
470 
471     if (sflag) {		/* add suffix */
472 	new = newbuf;
473 	(void) strcpy(new, key);
474 	(void) strcat(new, pe->psuf);
475     } else
476 	new = key;
477     new = strsave(new);
478     for (i = pe->pdirs; i > loc; --i)
479 	pe->pdir[i] = pe->pdir[i-1];
480     if (loc > pe->pdirs)
481 	loc = pe->pdirs;
482     pe->pdir[loc] = new;
483     pe->pdirs++;
484 }
485 
486 /***********************************************
487  ***    D E L E T E   A   P A T H N A M E    ***
488  ***********************************************/
489 
490 static void
491 dcmd(path)			/* delete path */
492 char *path;
493 {
494     register int n;
495     register struct pelem *pe;
496 
497     for (pe = pathhead; pe; pe = pe->pnext) {
498 	n = locate(pe, path);
499 	if (n >= 0)
500 	    delete(pe, n);
501 	else
502 	    xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
503 		    path, pe->pname);
504     }
505 }
506 
507 static void
508 dncmd(n)			/* delete at position n */
509 int n;
510 {
511     register struct pelem *pe;
512 
513     for (pe = pathhead; pe; pe = pe->pnext) {
514 	if (n < pe->pdirs)
515 	    delete(pe, n);
516 	else
517 	    xprintf(CGETS(10, 5,
518 			    "setpath: %d not valid position in %s\n"),
519 		    n, pe->pname);
520     }
521 }
522 
523 static void
524 delete(pe, n)
525 register struct pelem *pe;
526 int n;
527 {
528     register int d;
529 
530     xfree((ptr_t) (pe->pdir[n]));
531     for (d = n; d < pe->pdirs - 1; d++)
532 	pe->pdir[d] = pe->pdir[d+1];
533     --pe->pdirs;
534 }
535 
536 /***********************************************
537  ***    C H A N G E   A   P A T H N A M E    ***
538  ***********************************************/
539 
540 static void
541 ccmd(inpath, path)		/* change inpath to path */
542 char *inpath, *path;
543 {
544     register int n;
545     register struct pelem *pe;
546 
547     for (pe = pathhead; pe; pe = pe->pnext) {
548 	n = locate(pe, inpath);
549 	if (n >= 0)
550 	    change(pe, n, path);
551 	else
552 	    xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"),
553 		    inpath, pe->pname);
554     }
555 }
556 
557 static void
558 cncmd(path, n)		/* change at position n to path */
559 char *path;
560 int n;
561 {
562     register struct pelem *pe;
563 
564     for (pe = pathhead; pe; pe = pe->pnext) {
565 	if (n < pe->pdirs)
566 	    change(pe, n, path);
567 	else
568 	    xprintf(CGETS(10, 5,
569 			    "setpath: %d not valid position in %s\n"),
570 		    n, pe->pname);
571     }
572 }
573 
574 static void
575 change(pe, loc, key)
576 register struct pelem *pe;
577 register int loc;
578 register char *key;
579 {
580     register char *new;
581     char newbuf[MAXPATHLEN+1];
582 
583     if (sflag) {		/* append suffix */
584 	new = newbuf;
585 	(void) strcpy(new, key);
586 	(void) strcat(new, pe->psuf);
587     } else
588 	new = key;
589     new = strsave(new);
590     xfree((ptr_t) (pe->pdir[loc]));
591     pe->pdir[loc] = new;
592 }
593 
594 /***************************************
595  ***    F I N D   P A T H N A M E    ***
596  ***************************************/
597 
598 static int
599 locate(pe, key)
600 register struct pelem *pe;
601 register char *key;
602 {
603     register int i;
604     register char *realkey;
605     char keybuf[MAXPATHLEN+1];
606 
607     if (sflag) {
608 	realkey = keybuf;
609 	(void) strcpy(realkey, key);
610 	(void) strcat(realkey, pe->psuf);
611     } else
612 	realkey = key;
613     for (i = 0; i < pe->pdirs; i++)
614 	if (strcmp(pe->pdir[i], realkey) == 0)
615 	    break;
616     return((i < pe->pdirs) ? i : -1);
617 }
618 #endif
619