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