/* * Copyright (c) 1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * THE SOFTWARE IS PROVIDED "AS IS" AND CARNEGIE MELLON UNIVERSITY * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT * SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Users of this software agree to return to Carnegie Mellon any * improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * * Export of this software is permitted only after complying with the * regulations of the U.S. Deptartment of Commerce relating to the * Export of Technical Data. */ /* * setpath --- smart interface for setting path variables * * usage: setpath(paths, cmds, localsyspath, dosuffix, printerrors) * char **paths, **cmds, *localsyspath; * int dosuffix, printerrors; * * The 'paths' argument is a list of pointers to path lists of the * form "name=value" where name is the name of the path and value * is a colon separated list of directories. There can never be * more than MAXDIRS (64) directories in a path. * * The 'cmds' argument may be a sequence of any of the following: * -r reset path to default * -i newpath insert newpath before localsyspath * -ia oldpath newpath insert newpath after oldpath * -ib oldpath newpath insert newpath before oldpath * -i# newpath insert newpath at position # * -d oldpath delete oldpath * -d# delete path at position # * -c oldpath newpath change oldpath to newpath * -c# newpath change position # to newpath * * The "-i newpath" command is equivilent to "-ib 'localsyspath' newpath". * * If 'dosuffix' is true, the appropriate suffix will be added to * all command operands for any system path in 'paths'. * * Both of the 'paths' and 'cmds' lists are terminated by a NULL * entry. * * if 'printerrors' is true, setpath will printf error diagnostics. * * WARNING !!!: Under no circumstances should anyone change this * module without fully understanding the impact on the C shell. * The C shell has it's own malloc and printf routines and this * module was carefully written taking that into account. Do not * use any stdio routines from this module except printf. * ********************************************************************** * HISTORY * * Revision 1.4 90/12/11 17:58:44 mja * Add copyright/disclaimer for distribution. * * 05-Jun-88 Glenn Marcy (gm0w) at Carnegie-Mellon University * Make all non-entry points static. * * 30-Apr-88 Glenn Marcy (gm0w) at Carnegie-Mellon University * Added -r switch to reset paths to their default values. * * 06-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University * Created from old setpath program for the shell. * ********************************************************************** */ #include "sh.h" RCSID("$Id: ma.setp.c,v 1.12 1996/04/26 19:18:36 christos Exp $") #ifdef MACH #define MAXDIRS 64 /* max directories on a path */ #ifndef NULL # define NULL 0 #endif static int npaths; /* # pathlist arguments */ static struct pelem { struct pelem *pnext; /* pointer to next path */ char *pname; /* name of pathlist */ char *psuf; /* suffix for pathlist */ char *pdef; /* default for pathlist */ int pdirs; /* # directories on each pathlist */ char *pdir[MAXDIRS]; /* directory names for each pathlist */ } *pathhead = NULL; static struct { char *name; char *suffix; char *defalt; } syspath[] = { "PATH", "/bin", ":/usr/ucb:/bin:/usr/bin", "CPATH", "/include", ":/usr/include", "LPATH", "/lib", ":/lib:/usr/lib", "MPATH", "/man", ":/usr/man", "EPATH", "/maclib", "", 0, 0, 0 }; static int sflag; static int eflag; #define INVALID { \ if (eflag) xprintf(CGETS(10, 1, \ "setpath: invalid command '%s'.\n"), cmd); \ freepaths(); \ return(-1); \ } #define TOOFEW { \ if (eflag) xprintf(CGETS(10, 2, \ "setpath: insufficient arguments to command '%s'.\n"), cmd); \ freepaths(); \ return(-1); \ } static int initpaths __P((char **)); static void savepaths __P((char **)); static void freepaths __P((void)); static void rcmd __P((char *)); static void icmd __P((char *, char *)); static void iacmd __P((char *, char *)); static void ibcmd __P((char *, char *)); static void incmd __P((char *, int)); static void insert __P((struct pelem *, int, char *)); static void dcmd __P((char *)); static void dncmd __P((int)); static void delete __P((struct pelem *, int)); static void ccmd __P((char *, char *)); static void cncmd __P((char *, int)); static void change __P((struct pelem *, int, char *)); static int locate __P((struct pelem *, char *)); int setpath(paths, cmds, localsyspath, dosuffix, printerrors) register char **paths, **cmds, *localsyspath; int dosuffix, printerrors; { register char *cmd, *cmd1, *cmd2; register int ncmd; sflag = dosuffix; eflag = printerrors; if (initpaths(paths) < 0) return(-1); if (npaths == 0) return(0); for (ncmd = 0; cmd = cmds[ncmd]; ncmd++) { if (cmd[0] != '-') INVALID; cmd1 = cmds[ncmd+1]; cmd2 = cmds[ncmd+2]; switch (cmd[1]) { case 'r': if (cmd[2] != '\0') INVALID; rcmd(localsyspath); break; case 'i': if (cmd[2] == '\0') { ncmd++; if (cmd1 == NULL) TOOFEW; icmd(cmd1, localsyspath); } else if (isdigit(cmd[2])) { ncmd++; if (cmd1 == NULL) TOOFEW; incmd(cmd1, atoi(cmd+2)); } else if (cmd[3] != '\0' || (cmd[2] != 'a' && cmd[2] != 'b')) { INVALID; } else { ncmd += 2; if (cmd1 == NULL || cmd2 == NULL) TOOFEW; if (cmd[2] == 'a') iacmd(cmd1, cmd2); else ibcmd(cmd1, cmd2); } break; case 'd': if (cmd[2] == '\0') { ncmd++; if (cmd1 == NULL) TOOFEW; dcmd(cmd1); } else if (isdigit(cmd[2])) dncmd(atoi(cmd+2)); else { INVALID; } break; case 'c': if (cmd[2] == '\0') { ncmd += 2; if (cmd1 == NULL || cmd2 == NULL) TOOFEW; ccmd(cmd1, cmd2); } else if (isdigit(cmd[2])) { ncmd++; if (cmd1 == NULL) TOOFEW; cncmd(cmd1, atoi(cmd+2)); } else { INVALID; } break; default: INVALID; } } savepaths(paths); freepaths(); return(0); } static int initpaths(paths) register char **paths; { register char *path, *val, *p, *q; register int i, done; register struct pelem *pe, *pathend; freepaths(); for (npaths = 0; path = paths[npaths]; npaths++) { val = index(path, '='); if (val == NULL) { if (eflag) xprintf(CGETS(10, 3, "setpath: value missing in path '%s'\n"), path); freepaths(); return(-1); } *val++ = '\0'; pe = (struct pelem *)xmalloc((unsigned)(sizeof(struct pelem))); setzero((char *) pe, sizeof(struct pelem)); if (pathhead == NULL) pathhead = pathend = pe; else { pathend->pnext = pe; pathend = pe; } p = strsave(path); pe->pname = p; pe->psuf = ""; pe->pdef = ""; for (i = 0; syspath[i].name; i++) if (strcmp(pe->pname, syspath[i].name) == 0) { pe->psuf = syspath[i].suffix; pe->pdef = syspath[i].defalt; break; } q = val; for (;;) { q = index(p = q, ':'); done = (q == NULL); if (!done) *q++ = '\0'; p = strsave(p); pe->pdir[pe->pdirs] = p; pe->pdirs++; if (done) break; } } return(0); } static void savepaths(paths) register char **paths; { register char *p, *q; register int npath, i, len; register struct pelem *pe; for (npath = 0, pe = pathhead; pe; npath++, pe = pe->pnext) { len = strlen(pe->pname) + 1; if (pe->pdirs == 0) len++; else for (i = 0; i < pe->pdirs; i++) len += strlen(pe->pdir[i]) + 1; p = xmalloc((unsigned)len); paths[npath] = p; for (q = pe->pname; *p = *q; p++, q++); *p++ = '='; if (pe->pdirs != 0) { for (i = 0; i < pe->pdirs; i++) { for (q = pe->pdir[i]; *p = *q; p++, q++); *p++ = ':'; } p--; } *p = '\0'; } } static void freepaths() { register char *p; register int i; register struct pelem *pe; if (npaths == 0 || pathhead == NULL) return; while (pe = pathhead) { if (pe->pname) { for (i = 0; i < pe->pdirs; i++) { if (pe->pdir[i] == NULL) continue; p = pe->pdir[i]; pe->pdir[i] = NULL; xfree((ptr_t) p); } pe->pdirs = 0; p = pe->pname; pe->pname = NULL; xfree((ptr_t) p); } pathhead = pe->pnext; xfree((ptr_t) pe); } npaths = 0; } /*********************************************** *** R E S E T A P A T H N A M E *** ***********************************************/ static void rcmd(localsyspath) /* reset path with localsyspath */ char *localsyspath; { register int n, done; register char *new, *p; register struct pelem *pe; char newbuf[MAXPATHLEN+1]; for (pe = pathhead; pe; pe = pe->pnext) { new = newbuf; *new = '\0'; if (localsyspath != NULL) { *new = ':'; (void) strcpy(new + 1, localsyspath); (void) strcat(new, pe->psuf); } (void) strcat(new, pe->pdef); for (n = 0; n < pe->pdirs; n++) { if (pe->pdir[n] == NULL) continue; p = pe->pdir[n]; pe->pdir[n] = NULL; xfree((ptr_t) p); } pe->pdirs = 0; for (;;) { new = index(p = new, ':'); done = (new == NULL); if (!done) *new++ = '\0'; p = strsave(p); pe->pdir[pe->pdirs] = p; pe->pdirs++; if (done) break; } } } /*********************************************** *** I N S E R T A P A T H N A M E *** ***********************************************/ static void icmd(path, localsyspath) /* insert path before localsyspath */ char *path, *localsyspath; { register int n; register char *new; register struct pelem *pe; char newbuf[MAXPATHLEN+1]; for (pe = pathhead; pe; pe = pe->pnext) { if (sflag) new = localsyspath; else { new = newbuf; (void) strcpy(new, localsyspath); (void) strcat(new, pe->psuf); } n = locate(pe, new); if (n >= 0) insert(pe, n, path); else insert(pe, 0, path); } } static void iacmd(inpath, path) /* insert path after inpath */ char *inpath, *path; { register int n; register struct pelem *pe; for (pe = pathhead; pe; pe = pe->pnext) { n = locate(pe, inpath); if (n >= 0) insert(pe, n + 1, path); else xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"), inpath, pe->pname); } } static void ibcmd(inpath, path) /* insert path before inpath */ char *inpath, *path; { register int n; register struct pelem *pe; for (pe = pathhead; pe; pe = pe->pnext) { n = locate(pe, inpath); if (n >= 0) insert(pe, n, path); else xprintf(CGETS(10, 4, "setpath: %s not found in %s\n", inpath, pe->pname)); } } static void incmd(path, n) /* insert path at position n */ char *path; int n; { register struct pelem *pe; for (pe = pathhead; pe; pe = pe->pnext) insert(pe, n, path); } static void insert(pe, loc, key) register struct pelem *pe; register int loc; register char *key; { register int i; register char *new; char newbuf[2000]; if (sflag) { /* add suffix */ new = newbuf; (void) strcpy(new, key); (void) strcat(new, pe->psuf); } else new = key; new = strsave(new); for (i = pe->pdirs; i > loc; --i) pe->pdir[i] = pe->pdir[i-1]; if (loc > pe->pdirs) loc = pe->pdirs; pe->pdir[loc] = new; pe->pdirs++; } /*********************************************** *** D E L E T E A P A T H N A M E *** ***********************************************/ static void dcmd(path) /* delete path */ char *path; { register int n; register struct pelem *pe; for (pe = pathhead; pe; pe = pe->pnext) { n = locate(pe, path); if (n >= 0) delete(pe, n); else xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"), path, pe->pname); } } static void dncmd(n) /* delete at position n */ int n; { register struct pelem *pe; for (pe = pathhead; pe; pe = pe->pnext) { if (n < pe->pdirs) delete(pe, n); else xprintf(CGETS(10, 5, "setpath: %d not valid position in %s\n"), n, pe->pname); } } static void delete(pe, n) register struct pelem *pe; int n; { register int d; xfree((ptr_t) (pe->pdir[n])); for (d = n; d < pe->pdirs - 1; d++) pe->pdir[d] = pe->pdir[d+1]; --pe->pdirs; } /*********************************************** *** C H A N G E A P A T H N A M E *** ***********************************************/ static void ccmd(inpath, path) /* change inpath to path */ char *inpath, *path; { register int n; register struct pelem *pe; for (pe = pathhead; pe; pe = pe->pnext) { n = locate(pe, inpath); if (n >= 0) change(pe, n, path); else xprintf(CGETS(10, 4, "setpath: %s not found in %s\n"), inpath, pe->pname); } } static void cncmd(path, n) /* change at position n to path */ char *path; int n; { register struct pelem *pe; for (pe = pathhead; pe; pe = pe->pnext) { if (n < pe->pdirs) change(pe, n, path); else xprintf(CGETS(10, 5, "setpath: %d not valid position in %s\n"), n, pe->pname); } } static void change(pe, loc, key) register struct pelem *pe; register int loc; register char *key; { register char *new; char newbuf[MAXPATHLEN+1]; if (sflag) { /* append suffix */ new = newbuf; (void) strcpy(new, key); (void) strcat(new, pe->psuf); } else new = key; new = strsave(new); xfree((ptr_t) (pe->pdir[loc])); pe->pdir[loc] = new; } /*************************************** *** F I N D P A T H N A M E *** ***************************************/ static int locate(pe, key) register struct pelem *pe; register char *key; { register int i; register char *realkey; char keybuf[MAXPATHLEN+1]; if (sflag) { realkey = keybuf; (void) strcpy(realkey, key); (void) strcat(realkey, pe->psuf); } else realkey = key; for (i = 0; i < pe->pdirs; i++) if (strcmp(pe->pdir[i], realkey) == 0) break; return((i < pe->pdirs) ? i : -1); } #endif