Merge from vendor branch TCPDUMP:
[dragonfly.git] / contrib / tcsh / ma.setp.c
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