ma.setp.c revision 195609
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"
85RCSID("$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
94static int npaths;		/* # pathlist arguments */
95
96static 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
105static 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
118static int sflag;
119static 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
135static int initpaths	(char **);
136static void savepaths	(char **);
137static void freepaths	(void);
138static void tcsh_rcmd	(char *);
139static void icmd	(char *, char *);
140static void iacmd	(char *, char *);
141static void ibcmd	(char *, char *);
142static void incmd	(char *, int);
143static void insert	(struct pelem *, int, char *);
144static void dcmd	(char *);
145static void dncmd	(int);
146static void delete	(struct pelem *, int);
147static void ccmd	(char *, char *);
148static void cncmd	(char *, int);
149static void change	(struct pelem *, int, char *);
150static int locate	(struct pelem *, char *);
151
152
153
154int
155setpath(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
231static int
232initpaths(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
283static void
284savepaths(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
311static void
312freepaths(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
344static void
345tcsh_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
387static void
388icmd(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
411static void
412iacmd(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
427static void
428ibcmd(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
443static void
444incmd(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
452static void
453insert(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
478static void
479dcmd(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
494static void
495dncmd(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
509static void
510delete(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
524static void
525ccmd(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
540static void
541cncmd(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
555static void
556change(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
576static int
577locate(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