ma.setp.c revision 145479
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("$Id: ma.setp.c,v 1.14 2004/08/04 17:12:28 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	__P((char **));
136static void savepaths	__P((char **));
137static void freepaths	__P((void));
138static void rcmd	__P((char *));
139static void icmd	__P((char *, char *));
140static void iacmd	__P((char *, char *));
141static void ibcmd	__P((char *, char *));
142static void incmd	__P((char *, int));
143static void insert	__P((struct pelem *, int, char *));
144static void dcmd	__P((char *));
145static void dncmd	__P((int));
146static void delete	__P((struct pelem *, int));
147static void ccmd	__P((char *, char *));
148static void cncmd	__P((char *, int));
149static void change	__P((struct pelem *, int, char *));
150static int locate	__P((struct pelem *, char *));
151
152
153
154int
155setpath(paths, cmds, localsyspath, dosuffix, printerrors)
156char **paths, **cmds, *localsyspath;
157int dosuffix, printerrors;
158{
159    char *cmd, *cmd1, *cmd2;
160    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
232static int
233initpaths(paths)
234char **paths;
235{
236    char *path, *val, *p, *q;
237    int i, done;
238    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
285static void
286savepaths(paths)
287char **paths;
288{
289    char *p, *q;
290    int npath, i, len;
291    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
314static void
315freepaths()
316{
317    char *p;
318    int i;
319    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
347static void
348rcmd(localsyspath)		/* reset path with localsyspath */
349char *localsyspath;
350{
351    int n, done;
352    char *new, *p;
353    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
391static void
392icmd(path, localsyspath)	/* insert path before localsyspath */
393char *path, *localsyspath;
394{
395    int n;
396    char *new;
397    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
416static void
417iacmd(inpath, path)		/* insert path after inpath */
418char *inpath, *path;
419{
420    int n;
421    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
433static void
434ibcmd(inpath, path)		/* insert path before inpath */
435char *inpath, *path;
436{
437    int n;
438    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
450static void
451incmd(path, n)			/* insert path at position n */
452char *path;
453int n;
454{
455    struct pelem *pe;
456
457    for (pe = pathhead; pe; pe = pe->pnext)
458	insert(pe, n, path);
459}
460
461static void
462insert(pe, loc, key)
463struct pelem *pe;
464int loc;
465char *key;
466{
467    int i;
468    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
490static void
491dcmd(path)			/* delete path */
492char *path;
493{
494    int n;
495    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
507static void
508dncmd(n)			/* delete at position n */
509int n;
510{
511    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
523static void
524delete(pe, n)
525struct pelem *pe;
526int n;
527{
528    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
540static void
541ccmd(inpath, path)		/* change inpath to path */
542char *inpath, *path;
543{
544    int n;
545    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
557static void
558cncmd(path, n)		/* change at position n to path */
559char *path;
560int n;
561{
562    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
574static void
575change(pe, loc, key)
576struct pelem *pe;
577int loc;
578char *key;
579{
580    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
598static int
599locate(pe, key)
600struct pelem *pe;
601char *key;
602{
603    int i;
604    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