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