Commit | Line | Data |
---|---|---|
761330fe DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
2ae9f53f | 7 | #ifndef lint |
751b30cd | 8 | static char *sccsid = "@(#)names.c 5.5 (Berkeley) %G%"; |
761330fe | 9 | #endif not lint |
65d3742f KS |
10 | |
11 | /* | |
12 | * Mail -- a mail program | |
13 | * | |
14 | * Handle name lists. | |
15 | */ | |
16 | ||
17 | #include "rcv.h" | |
828615a1 | 18 | #include <sys/wait.h> |
65d3742f | 19 | |
65d3742f KS |
20 | /* |
21 | * Allocate a single element of a name list, | |
22 | * initialize its name field to the passed | |
23 | * name and return it. | |
24 | */ | |
25 | ||
26 | struct name * | |
27 | nalloc(str) | |
28 | char str[]; | |
29 | { | |
30 | register struct name *np; | |
31 | ||
32 | np = (struct name *) salloc(sizeof *np); | |
33 | np->n_flink = NIL; | |
34 | np->n_blink = NIL; | |
35 | np->n_type = -1; | |
36 | np->n_name = savestr(str); | |
37 | return(np); | |
38 | } | |
39 | ||
40 | /* | |
41 | * Find the tail of a list and return it. | |
42 | */ | |
43 | ||
44 | struct name * | |
45 | tailof(name) | |
46 | struct name *name; | |
47 | { | |
48 | register struct name *np; | |
49 | ||
50 | np = name; | |
51 | if (np == NIL) | |
52 | return(NIL); | |
53 | while (np->n_flink != NIL) | |
54 | np = np->n_flink; | |
55 | return(np); | |
56 | } | |
57 | ||
58 | /* | |
59 | * Extract a list of names from a line, | |
60 | * and make a list of names from it. | |
61 | * Return the list or NIL if none found. | |
62 | */ | |
63 | ||
64 | struct name * | |
65 | extract(line, ntype) | |
66 | char line[]; | |
67 | { | |
68 | register char *cp; | |
69 | register struct name *top, *np, *t; | |
70 | char nbuf[BUFSIZ], abuf[BUFSIZ]; | |
71 | ||
72 | if (line == NOSTR || strlen(line) == 0) | |
73 | return(NIL); | |
74 | top = NIL; | |
75 | np = NIL; | |
76 | cp = line; | |
77 | while ((cp = yankword(cp, nbuf)) != NOSTR) { | |
78 | if (np != NIL && equal(nbuf, "at")) { | |
751b30cd | 79 | (void) strcpy(abuf, nbuf); |
65d3742f | 80 | if ((cp = yankword(cp, nbuf)) == NOSTR) { |
751b30cd | 81 | (void) strcpy(nbuf, abuf); |
65d3742f KS |
82 | goto normal; |
83 | } | |
751b30cd | 84 | (void) strcpy(abuf, np->n_name); |
65d3742f | 85 | stradd(abuf, '@'); |
751b30cd | 86 | (void) strcat(abuf, nbuf); |
65d3742f KS |
87 | np->n_name = savestr(abuf); |
88 | continue; | |
89 | } | |
90 | normal: | |
91 | t = nalloc(nbuf); | |
92 | t->n_type = ntype; | |
93 | if (top == NIL) | |
94 | top = t; | |
95 | else | |
96 | np->n_flink = t; | |
97 | t->n_blink = np; | |
98 | np = t; | |
99 | } | |
100 | return(top); | |
101 | } | |
102 | ||
103 | /* | |
104 | * Turn a list of names into a string of the same names. | |
105 | */ | |
106 | ||
107 | char * | |
108 | detract(np, ntype) | |
109 | register struct name *np; | |
110 | { | |
111 | register int s; | |
112 | register char *cp, *top; | |
113 | register struct name *p; | |
114 | register int comma; | |
115 | ||
116 | comma = ntype & GCOMMA; | |
117 | if (np == NIL) | |
118 | return(NOSTR); | |
119 | ntype &= ~GCOMMA; | |
120 | s = 0; | |
121 | if (debug && comma) | |
122 | fprintf(stderr, "detract asked to insert commas\n"); | |
123 | for (p = np; p != NIL; p = p->n_flink) { | |
124 | if (ntype && (p->n_type & GMASK) != ntype) | |
125 | continue; | |
126 | s += strlen(p->n_name) + 1; | |
127 | if (comma) | |
128 | s++; | |
129 | } | |
130 | if (s == 0) | |
131 | return(NOSTR); | |
132 | s += 2; | |
133 | top = salloc(s); | |
134 | cp = top; | |
135 | for (p = np; p != NIL; p = p->n_flink) { | |
136 | if (ntype && (p->n_type & GMASK) != ntype) | |
137 | continue; | |
138 | cp = copy(p->n_name, cp); | |
139 | if (comma && p->n_flink != NIL) | |
140 | *cp++ = ','; | |
141 | *cp++ = ' '; | |
142 | } | |
143 | *--cp = 0; | |
144 | if (comma && *--cp == ',') | |
145 | *cp = 0; | |
146 | return(top); | |
147 | } | |
148 | ||
149 | /* | |
150 | * Grab a single word (liberal word) | |
151 | * Throw away things between ()'s. | |
152 | */ | |
153 | ||
154 | char * | |
155 | yankword(ap, wbuf) | |
156 | char *ap, wbuf[]; | |
157 | { | |
158 | register char *cp, *cp2; | |
159 | ||
116f92bd | 160 | cp = ap; |
65d3742f | 161 | do { |
116f92bd S |
162 | while (*cp && any(*cp, " \t,")) |
163 | cp++; | |
65d3742f | 164 | if (*cp == '(') { |
116f92bd S |
165 | register int nesting = 0; |
166 | ||
167 | while (*cp != '\0') { | |
168 | switch (*cp++) { | |
169 | case '(': | |
170 | nesting++; | |
171 | break; | |
172 | case ')': | |
173 | --nesting; | |
174 | break; | |
175 | } | |
176 | if (nesting <= 0) | |
177 | break; | |
178 | } | |
65d3742f KS |
179 | } |
180 | if (*cp == '\0') | |
181 | return(NOSTR); | |
182 | } while (any(*cp, " \t,(")); | |
183 | for (cp2 = wbuf; *cp && !any(*cp, " \t,("); *cp2++ = *cp++) | |
184 | ; | |
185 | *cp2 = '\0'; | |
186 | return(cp); | |
187 | } | |
188 | ||
189 | /* | |
190 | * Verify that all the users in the list of names are | |
191 | * legitimate. Bitch about and delink those who aren't. | |
192 | */ | |
193 | ||
194 | struct name * | |
195 | verify(names) | |
196 | struct name *names; | |
197 | { | |
ac57be53 | 198 | #ifdef SENDMAIL |
828615a1 | 199 | |
65d3742f KS |
200 | return(names); |
201 | #else | |
828615a1 EW |
202 | register struct name *np, *top, *t, *x; |
203 | register char *cp; | |
204 | ||
65d3742f KS |
205 | top = names; |
206 | np = names; | |
207 | while (np != NIL) { | |
208 | if (np->n_type & GDEL) { | |
209 | np = np->n_flink; | |
210 | continue; | |
211 | } | |
212 | for (cp = "!:@^"; *cp; cp++) | |
213 | if (any(*cp, np->n_name)) | |
214 | break; | |
215 | if (*cp != 0) { | |
216 | np = np->n_flink; | |
217 | continue; | |
218 | } | |
219 | cp = np->n_name; | |
220 | while (*cp == '\\') | |
221 | cp++; | |
222 | if (equal(cp, "msgs") || | |
223 | getuserid(cp) != -1) { | |
224 | np = np->n_flink; | |
225 | continue; | |
226 | } | |
227 | fprintf(stderr, "Can't send to %s\n", np->n_name); | |
228 | senderr++; | |
229 | if (np == top) { | |
230 | top = np->n_flink; | |
231 | if (top != NIL) | |
232 | top->n_blink = NIL; | |
233 | np = top; | |
234 | continue; | |
235 | } | |
236 | x = np->n_blink; | |
237 | t = np->n_flink; | |
238 | x->n_flink = t; | |
239 | if (t != NIL) | |
240 | t->n_blink = x; | |
241 | np = t; | |
242 | } | |
243 | return(top); | |
244 | #endif | |
245 | } | |
246 | ||
247 | /* | |
248 | * For each recipient in the passed name list with a / | |
249 | * in the name, append the message to the end of the named file | |
250 | * and remove him from the recipient list. | |
251 | * | |
252 | * Recipients whose name begins with | are piped through the given | |
253 | * program and removed. | |
254 | */ | |
255 | ||
256 | struct name * | |
257 | outof(names, fo, hp) | |
258 | struct name *names; | |
259 | FILE *fo; | |
260 | struct header *hp; | |
261 | { | |
262 | register int c; | |
828615a1 EW |
263 | register struct name *np, *top; |
264 | #ifdef CRAZYWOW | |
265 | register struct name *t, *x; | |
266 | #endif | |
267 | time_t now, time(); | |
65d3742f KS |
268 | char *date, *fname, *shell, *ctime(); |
269 | FILE *fout, *fin; | |
828615a1 | 270 | int ispipe; |
65d3742f | 271 | extern char tempEdit[]; |
828615a1 | 272 | union wait s; |
65d3742f KS |
273 | |
274 | top = names; | |
275 | np = names; | |
751b30cd | 276 | (void) time(&now); |
65d3742f KS |
277 | date = ctime(&now); |
278 | while (np != NIL) { | |
5cf80950 | 279 | if (!isfileaddr(np->n_name) && np->n_name[0] != '|') { |
65d3742f KS |
280 | np = np->n_flink; |
281 | continue; | |
282 | } | |
283 | ispipe = np->n_name[0] == '|'; | |
284 | if (ispipe) | |
285 | fname = np->n_name+1; | |
286 | else | |
287 | fname = expand(np->n_name); | |
288 | ||
289 | /* | |
290 | * See if we have copied the complete message out yet. | |
291 | * If not, do so. | |
292 | */ | |
293 | ||
294 | if (image < 0) { | |
295 | if ((fout = fopen(tempEdit, "a")) == NULL) { | |
296 | perror(tempEdit); | |
297 | senderr++; | |
298 | goto cant; | |
299 | } | |
300 | image = open(tempEdit, 2); | |
751b30cd | 301 | (void) unlink(tempEdit); |
65d3742f KS |
302 | if (image < 0) { |
303 | perror(tempEdit); | |
304 | senderr++; | |
305 | goto cant; | |
306 | } | |
307 | else { | |
308 | rewind(fo); | |
309 | fprintf(fout, "From %s %s", myname, date); | |
310 | puthead(hp, fout, GTO|GSUBJECT|GCC|GNL); | |
311 | while ((c = getc(fo)) != EOF) | |
751b30cd | 312 | (void) putc(c, fout); |
65d3742f | 313 | rewind(fo); |
751b30cd EW |
314 | (void) putc('\n', fout); |
315 | (void) fflush(fout); | |
65d3742f KS |
316 | if (ferror(fout)) |
317 | perror(tempEdit); | |
751b30cd | 318 | (void) fclose(fout); |
65d3742f KS |
319 | } |
320 | } | |
321 | ||
322 | /* | |
323 | * Now either copy "image" to the desired file | |
324 | * or give it as the standard input to the desired | |
325 | * program as appropriate. | |
326 | */ | |
327 | ||
328 | if (ispipe) { | |
751b30cd | 329 | (void) wait(&s); |
828615a1 | 330 | switch (fork()) { |
65d3742f | 331 | case 0: |
751b30cd EW |
332 | (void) signal(SIGHUP, SIG_IGN); |
333 | (void) signal(SIGINT, SIG_IGN); | |
334 | (void) signal(SIGQUIT, SIG_IGN); | |
335 | (void) close(0); | |
336 | (void) dup(image); | |
337 | (void) close(image); | |
65d3742f KS |
338 | if ((shell = value("SHELL")) == NOSTR) |
339 | shell = SHELL; | |
340 | execl(shell, shell, "-c", fname, 0); | |
341 | perror(shell); | |
342 | exit(1); | |
343 | break; | |
344 | ||
345 | case -1: | |
346 | perror("fork"); | |
347 | senderr++; | |
348 | goto cant; | |
349 | } | |
350 | } | |
351 | else { | |
352 | if ((fout = fopen(fname, "a")) == NULL) { | |
353 | perror(fname); | |
354 | senderr++; | |
355 | goto cant; | |
356 | } | |
357 | fin = Fdopen(image, "r"); | |
358 | if (fin == NULL) { | |
359 | fprintf(stderr, "Can't reopen image\n"); | |
751b30cd | 360 | (void) fclose(fout); |
65d3742f KS |
361 | senderr++; |
362 | goto cant; | |
363 | } | |
364 | rewind(fin); | |
365 | while ((c = getc(fin)) != EOF) | |
751b30cd | 366 | (void) putc(c, fout); |
65d3742f KS |
367 | if (ferror(fout)) |
368 | senderr++, perror(fname); | |
751b30cd EW |
369 | (void) fclose(fout); |
370 | (void) fclose(fin); | |
65d3742f KS |
371 | } |
372 | ||
373 | cant: | |
374 | ||
375 | /* | |
376 | * In days of old we removed the entry from the | |
377 | * the list; now for sake of header expansion | |
378 | * we leave it in and mark it as deleted. | |
379 | */ | |
380 | ||
381 | #ifdef CRAZYWOW | |
382 | if (np == top) { | |
383 | top = np->n_flink; | |
384 | if (top != NIL) | |
385 | top->n_blink = NIL; | |
386 | np = top; | |
387 | continue; | |
388 | } | |
389 | x = np->n_blink; | |
390 | t = np->n_flink; | |
391 | x->n_flink = t; | |
392 | if (t != NIL) | |
393 | t->n_blink = x; | |
394 | np = t; | |
395 | #endif | |
396 | ||
397 | np->n_type |= GDEL; | |
398 | np = np->n_flink; | |
399 | } | |
400 | if (image >= 0) { | |
751b30cd | 401 | (void) close(image); |
65d3742f KS |
402 | image = -1; |
403 | } | |
404 | return(top); | |
405 | } | |
406 | ||
5cf80950 KS |
407 | /* |
408 | * Determine if the passed address is a local "send to file" address. | |
409 | * If any of the network metacharacters precedes any slashes, it can't | |
410 | * be a filename. We cheat with .'s to allow path names like ./... | |
411 | */ | |
412 | isfileaddr(name) | |
413 | char *name; | |
414 | { | |
415 | register char *cp; | |
416 | extern char *metanet; | |
417 | ||
418 | if (any('@', name)) | |
419 | return(0); | |
1c617162 KS |
420 | if (*name == '+') |
421 | return(1); | |
5cf80950 KS |
422 | for (cp = name; *cp; cp++) { |
423 | if (*cp == '.') | |
424 | continue; | |
425 | if (any(*cp, metanet)) | |
426 | return(0); | |
427 | if (*cp == '/') | |
428 | return(1); | |
429 | } | |
430 | return(0); | |
431 | } | |
432 | ||
65d3742f KS |
433 | /* |
434 | * Map all of the aliased users in the invoker's mailrc | |
435 | * file and insert them into the list. | |
436 | * Changed after all these months of service to recursively | |
437 | * expand names (2/14/80). | |
438 | */ | |
439 | ||
440 | struct name * | |
441 | usermap(names) | |
442 | struct name *names; | |
443 | { | |
444 | register struct name *new, *np, *cp; | |
65d3742f KS |
445 | struct grouphead *gh; |
446 | register int metoo; | |
447 | ||
448 | new = NIL; | |
449 | np = names; | |
65d3742f KS |
450 | metoo = (value("metoo") != NOSTR); |
451 | while (np != NIL) { | |
452 | if (np->n_name[0] == '\\') { | |
453 | cp = np->n_flink; | |
454 | new = put(new, np); | |
455 | np = cp; | |
456 | continue; | |
457 | } | |
458 | gh = findgroup(np->n_name); | |
459 | cp = np->n_flink; | |
460 | if (gh != NOGRP) | |
461 | new = gexpand(new, gh, metoo, np->n_type); | |
462 | else | |
463 | new = put(new, np); | |
464 | np = cp; | |
465 | } | |
466 | return(new); | |
467 | } | |
468 | ||
469 | /* | |
470 | * Recursively expand a group name. We limit the expansion to some | |
471 | * fixed level to keep things from going haywire. | |
472 | * Direct recursion is not expanded for convenience. | |
473 | */ | |
474 | ||
475 | struct name * | |
476 | gexpand(nlist, gh, metoo, ntype) | |
477 | struct name *nlist; | |
478 | struct grouphead *gh; | |
479 | { | |
480 | struct group *gp; | |
481 | struct grouphead *ngh; | |
482 | struct name *np; | |
483 | static int depth; | |
484 | char *cp; | |
485 | ||
486 | if (depth > MAXEXP) { | |
487 | printf("Expanding alias to depth larger than %d\n", MAXEXP); | |
488 | return(nlist); | |
489 | } | |
490 | depth++; | |
491 | for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { | |
492 | cp = gp->ge_name; | |
493 | if (*cp == '\\') | |
494 | goto quote; | |
495 | if (strcmp(cp, gh->g_name) == 0) | |
496 | goto quote; | |
497 | if ((ngh = findgroup(cp)) != NOGRP) { | |
498 | nlist = gexpand(nlist, ngh, metoo, ntype); | |
499 | continue; | |
500 | } | |
501 | quote: | |
502 | np = nalloc(cp); | |
503 | np->n_type = ntype; | |
504 | /* | |
505 | * At this point should allow to expand | |
506 | * to self if only person in group | |
507 | */ | |
508 | if (gp == gh->g_list && gp->ge_link == NOGE) | |
509 | goto skip; | |
510 | if (!metoo && strcmp(cp, myname) == 0) | |
511 | np->n_type |= GDEL; | |
512 | skip: | |
513 | nlist = put(nlist, np); | |
514 | } | |
515 | depth--; | |
516 | return(nlist); | |
517 | } | |
518 | ||
519 | ||
520 | ||
521 | /* | |
522 | * Compute the length of the passed name list and | |
523 | * return it. | |
524 | */ | |
525 | ||
526 | lengthof(name) | |
527 | struct name *name; | |
528 | { | |
529 | register struct name *np; | |
530 | register int c; | |
531 | ||
532 | for (c = 0, np = name; np != NIL; c++, np = np->n_flink) | |
533 | ; | |
534 | return(c); | |
535 | } | |
536 | ||
537 | /* | |
538 | * Concatenate the two passed name lists, return the result. | |
539 | */ | |
540 | ||
541 | struct name * | |
542 | cat(n1, n2) | |
543 | struct name *n1, *n2; | |
544 | { | |
545 | register struct name *tail; | |
546 | ||
547 | if (n1 == NIL) | |
548 | return(n2); | |
549 | if (n2 == NIL) | |
550 | return(n1); | |
551 | tail = tailof(n1); | |
552 | tail->n_flink = n2; | |
553 | n2->n_blink = tail; | |
554 | return(n1); | |
555 | } | |
556 | ||
557 | /* | |
558 | * Unpack the name list onto a vector of strings. | |
559 | * Return an error if the name list won't fit. | |
560 | */ | |
561 | ||
562 | char ** | |
563 | unpack(np) | |
564 | struct name *np; | |
565 | { | |
566 | register char **ap, **top; | |
567 | register struct name *n; | |
65d3742f | 568 | char hbuf[10]; |
03c98b7d | 569 | int t, extra, metoo, verbose; |
65d3742f KS |
570 | |
571 | n = np; | |
572 | if ((t = lengthof(n)) == 0) | |
573 | panic("No names to unpack"); | |
574 | ||
575 | /* | |
576 | * Compute the number of extra arguments we will need. | |
577 | * We need at least two extra -- one for "mail" and one for | |
578 | * the terminating 0 pointer. Additional spots may be needed | |
579 | * to pass along -r and -f to the host mailer. | |
580 | */ | |
581 | ||
582 | extra = 2; | |
583 | if (rflag != NOSTR) | |
584 | extra += 2; | |
ac57be53 | 585 | #ifdef SENDMAIL |
65d3742f KS |
586 | extra++; |
587 | metoo = value("metoo") != NOSTR; | |
588 | if (metoo) | |
589 | extra++; | |
03c98b7d CL |
590 | verbose = value("verbose") != NOSTR; |
591 | if (verbose) | |
592 | extra++; | |
ac57be53 | 593 | #endif SENDMAIL |
65d3742f KS |
594 | if (hflag) |
595 | extra += 2; | |
751b30cd | 596 | top = (char **) salloc((t + extra) * sizeof *top); |
65d3742f KS |
597 | ap = top; |
598 | *ap++ = "send-mail"; | |
599 | if (rflag != NOSTR) { | |
600 | *ap++ = "-r"; | |
601 | *ap++ = rflag; | |
602 | } | |
ac57be53 | 603 | #ifdef SENDMAIL |
65d3742f KS |
604 | *ap++ = "-i"; |
605 | if (metoo) | |
606 | *ap++ = "-m"; | |
03c98b7d CL |
607 | if (verbose) |
608 | *ap++ = "-v"; | |
ac57be53 | 609 | #endif SENDMAIL |
65d3742f KS |
610 | if (hflag) { |
611 | *ap++ = "-h"; | |
751b30cd | 612 | *ap++ = savestr(sprintf(hbuf, "%d", hflag)); |
65d3742f KS |
613 | } |
614 | while (n != NIL) { | |
615 | if (n->n_type & GDEL) { | |
616 | n = n->n_flink; | |
617 | continue; | |
618 | } | |
6f63024f | 619 | *ap++ = n->n_name; |
65d3742f KS |
620 | n = n->n_flink; |
621 | } | |
622 | *ap = NOSTR; | |
623 | return(top); | |
624 | } | |
625 | ||
626 | /* | |
627 | * See if the user named himself as a destination | |
628 | * for outgoing mail. If so, set the global flag | |
629 | * selfsent so that we avoid removing his mailbox. | |
630 | */ | |
631 | ||
632 | mechk(names) | |
633 | struct name *names; | |
634 | { | |
635 | register struct name *np; | |
636 | ||
637 | for (np = names; np != NIL; np = np->n_flink) | |
20b5c5b1 | 638 | if ((np->n_type & GDEL) == 0 && equal(np->n_name, myname)) { |
65d3742f KS |
639 | selfsent++; |
640 | return; | |
641 | } | |
642 | } | |
643 | ||
644 | /* | |
645 | * Remove all of the duplicates from the passed name list by | |
646 | * insertion sorting them, then checking for dups. | |
647 | * Return the head of the new list. | |
648 | */ | |
649 | ||
650 | struct name * | |
651 | elide(names) | |
652 | struct name *names; | |
653 | { | |
654 | register struct name *np, *t, *new; | |
655 | struct name *x; | |
656 | ||
657 | if (names == NIL) | |
658 | return(NIL); | |
659 | new = names; | |
660 | np = names; | |
661 | np = np->n_flink; | |
662 | if (np != NIL) | |
663 | np->n_blink = NIL; | |
664 | new->n_flink = NIL; | |
665 | while (np != NIL) { | |
666 | t = new; | |
667 | while (nstrcmp(t->n_name, np->n_name) < 0) { | |
668 | if (t->n_flink == NIL) | |
669 | break; | |
670 | t = t->n_flink; | |
671 | } | |
672 | ||
673 | /* | |
674 | * If we ran out of t's, put the new entry after | |
675 | * the current value of t. | |
676 | */ | |
677 | ||
678 | if (nstrcmp(t->n_name, np->n_name) < 0) { | |
679 | t->n_flink = np; | |
680 | np->n_blink = t; | |
681 | t = np; | |
682 | np = np->n_flink; | |
683 | t->n_flink = NIL; | |
684 | continue; | |
685 | } | |
686 | ||
687 | /* | |
688 | * Otherwise, put the new entry in front of the | |
689 | * current t. If at the front of the list, | |
690 | * the new guy becomes the new head of the list. | |
691 | */ | |
692 | ||
693 | if (t == new) { | |
694 | t = np; | |
695 | np = np->n_flink; | |
696 | t->n_flink = new; | |
697 | new->n_blink = t; | |
698 | t->n_blink = NIL; | |
699 | new = t; | |
700 | continue; | |
701 | } | |
702 | ||
703 | /* | |
704 | * The normal case -- we are inserting into the | |
705 | * middle of the list. | |
706 | */ | |
707 | ||
708 | x = np; | |
709 | np = np->n_flink; | |
710 | x->n_flink = t; | |
711 | x->n_blink = t->n_blink; | |
712 | t->n_blink->n_flink = x; | |
713 | t->n_blink = x; | |
714 | } | |
715 | ||
716 | /* | |
717 | * Now the list headed up by new is sorted. | |
718 | * Go through it and remove duplicates. | |
719 | */ | |
720 | ||
721 | np = new; | |
722 | while (np != NIL) { | |
723 | t = np; | |
724 | while (t->n_flink!=NIL && | |
725 | icequal(np->n_name,t->n_flink->n_name)) | |
726 | t = t->n_flink; | |
727 | if (t == np || t == NIL) { | |
728 | np = np->n_flink; | |
729 | continue; | |
730 | } | |
731 | ||
732 | /* | |
733 | * Now t points to the last entry with the same name | |
734 | * as np. Make np point beyond t. | |
735 | */ | |
736 | ||
737 | np->n_flink = t->n_flink; | |
738 | if (t->n_flink != NIL) | |
739 | t->n_flink->n_blink = np; | |
740 | np = np->n_flink; | |
741 | } | |
742 | return(new); | |
743 | } | |
744 | ||
745 | /* | |
746 | * Version of strcmp which ignores case differences. | |
747 | */ | |
748 | ||
749 | nstrcmp(s1, s2) | |
750 | register char *s1, *s2; | |
751 | { | |
752 | register int c1, c2; | |
753 | ||
754 | do { | |
755 | c1 = *s1++; | |
756 | c2 = *s2++; | |
757 | } while (c1 && c1 == c2); | |
758 | return(c1 - c2); | |
759 | } | |
760 | ||
761 | /* | |
762 | * Put another node onto a list of names and return | |
763 | * the list. | |
764 | */ | |
765 | ||
766 | struct name * | |
767 | put(list, node) | |
768 | struct name *list, *node; | |
769 | { | |
770 | node->n_flink = list; | |
771 | node->n_blink = NIL; | |
772 | if (list != NIL) | |
773 | list->n_blink = node; | |
774 | return(node); | |
775 | } | |
776 | ||
777 | /* | |
778 | * Determine the number of elements in | |
779 | * a name list and return it. | |
780 | */ | |
781 | ||
782 | count(np) | |
783 | register struct name *np; | |
784 | { | |
785 | register int c = 0; | |
786 | ||
787 | while (np != NIL) { | |
788 | c++; | |
789 | np = np->n_flink; | |
790 | } | |
791 | return(c); | |
792 | } | |
793 | ||
794 | /* | |
03c98b7d CL |
795 | * Delete the given name from a namelist, using the passed |
796 | * function to compare the names. | |
65d3742f | 797 | */ |
65d3742f | 798 | struct name * |
03c98b7d | 799 | delname(np, name, cmpfun) |
65d3742f KS |
800 | register struct name *np; |
801 | char name[]; | |
03c98b7d | 802 | int (* cmpfun)(); |
65d3742f KS |
803 | { |
804 | register struct name *p; | |
805 | ||
806 | for (p = np; p != NIL; p = p->n_flink) | |
03c98b7d | 807 | if ((* cmpfun)(p->n_name, name)) { |
65d3742f KS |
808 | if (p->n_blink == NIL) { |
809 | if (p->n_flink != NIL) | |
810 | p->n_flink->n_blink = NIL; | |
811 | np = p->n_flink; | |
812 | continue; | |
813 | } | |
814 | if (p->n_flink == NIL) { | |
815 | if (p->n_blink != NIL) | |
816 | p->n_blink->n_flink = NIL; | |
817 | continue; | |
818 | } | |
819 | p->n_blink->n_flink = p->n_flink; | |
820 | p->n_flink->n_blink = p->n_blink; | |
821 | } | |
822 | return(np); | |
823 | } | |
824 | ||
825 | /* | |
826 | * Call the given routine on each element of the name | |
827 | * list, replacing said value if need be. | |
828 | */ | |
829 | ||
830 | mapf(np, from) | |
831 | register struct name *np; | |
832 | char *from; | |
833 | { | |
834 | register struct name *p; | |
835 | ||
836 | for (p = np; p != NIL; p = p->n_flink) | |
837 | p->n_name = netmap(p->n_name, from); | |
838 | } | |
839 | ||
840 | /* | |
841 | * Pretty print a name list | |
842 | * Uncomment it if you need it. | |
843 | */ | |
844 | ||
828615a1 | 845 | /* |
65d3742f KS |
846 | prettyprint(name) |
847 | struct name *name; | |
848 | { | |
849 | register struct name *np; | |
850 | ||
851 | np = name; | |
852 | while (np != NIL) { | |
853 | fprintf(stderr, "%s(%d) ", np->n_name, np->n_type); | |
854 | np = np->n_flink; | |
855 | } | |
856 | fprintf(stderr, "\n"); | |
857 | } | |
828615a1 | 858 | */ |