BSD 4_2 release
[unix-history] / usr / src / ucb / sendbug / bugfiler.c
CommitLineData
524aa063 1#ifndef lint
0f4556f1 2static char sccsid[] = "@(#)bugfiler.c 4.11 (Berkeley) 9/14/83";
524aa063
SL
3#endif
4
b7520dd0
RC
5/*
6 * Bug report processing program.
ae422d11
SL
7 * It is designed to be invoked by alias(5)
8 * and to be compatible with mh.
b7520dd0
RC
9 */
10
11#include <stdio.h>
12#include <ctype.h>
13#include <signal.h>
ae422d11
SL
14#include <pwd.h>
15
b7520dd0
RC
16#include <sys/types.h>
17#include <sys/stat.h>
80765673 18#include <sys/dir.h>
b7520dd0 19
ae422d11
SL
20#define BUGS_NAME "4bsd-bugs"
21#define BUGS_HOME "%ucbarpa@BERKELEY"
22#define MAILCMD "/usr/lib/sendmail -i -t"
23
c9f37f53 24char unixtomh[] = "/usr/new/lib/mh/unixtomh";
ae422d11
SL
25char *bugperson = "bugs";
26char *maildir = "mail";
b7520dd0
RC
27char ackfile[] = ".ack";
28char errfile[] = ".format";
29char sumfile[] = "summary";
30char logfile[] = "errors/log";
ae422d11 31char redistfile[] = ".redist";
b7520dd0
RC
32char tmpname[] = "BfXXXXXX";
33char draft[] = "RpXXXXXX";
ae422d11 34char disttmp[] = "RcXXXXXX";
b7520dd0 35
80765673 36char buf[8192];
b7520dd0
RC
37char folder[MAXNAMLEN];
38int num;
39int msg_prot = 0664;
40
41int debug;
42
43char *index();
44char *rindex();
45char *fixaddr();
ae422d11 46char *any();
b7520dd0
RC
47
48main(argc, argv)
49 char *argv[];
50{
51 register char *cp;
80765673
RC
52 register int n;
53 int pfd[2];
b7520dd0
RC
54
55 if (argc > 3) {
56 usage:
80765673 57 fprintf(stderr, "Usage: bugfiler [-d] [-mmsg_mode] [maildir]\n");
b7520dd0
RC
58 exit(1);
59 }
60 while (--argc > 0) {
61 cp = *++argv;
80765673
RC
62 if (*cp == '-')
63 switch (cp[1]) {
b7520dd0
RC
64 case 'd':
65 debug++;
66 break;
80765673
RC
67
68 case 'm': /* set message protection */
69 n = 0;
70 for (cp += 2; *cp >= '0' && *cp <= '7'; )
71 n = (n << 3) + (*cp++ - '0');
72 msg_prot = n & 0777;
73 break;
74
b7520dd0
RC
75 default:
76 goto usage;
77 }
78 else
79 maildir = cp;
80 }
80765673
RC
81 if (!debug)
82 freopen(logfile, "a", stderr);
83
ae422d11
SL
84 if (bugperson) {
85 struct passwd *pwd = getpwnam(bugperson);
86
87 if (pwd == NULL) {
88 fprintf(stderr, "%s: bugs person is unknown\n",
89 bugperson);
90 exit(1);
91 }
92 if (chdir(pwd->pw_dir) < 0) {
93 fprintf(stderr, "can't chdir to %s\n", pwd->pw_dir);
94 exit(1);
95 }
96 }
b7520dd0
RC
97 if (chdir(maildir) < 0) {
98 fprintf(stderr, "can't chdir to %s\n", maildir);
99 exit(1);
100 }
80765673
RC
101 umask(0);
102
103#ifdef UNIXCOMP
104 /*
105 * Convert UNIX style mail to mh style by filtering stdin through
106 * unixtomh.
107 */
108 if (pipe(pfd) >= 0) {
109 while ((n = fork()) == -1)
110 sleep(5);
111 if (n == 0) {
112 close(pfd[0]);
113 dup2(pfd[1], 1);
114 close(pfd[1]);
115 execl(unixtomh, "unixtomh", 0);
116 _exit(127);
117 }
118 close(pfd[1]);
119 dup2(pfd[0], 0);
120 close(pfd[0]);
121 }
122#endif
123 while (process())
124 ;
125 exit(0);
b7520dd0
RC
126}
127
80765673
RC
128/* states */
129
130#define EOM 0 /* End of message seen */
131#define FLD 1 /* Looking for header lines */
132#define BODY 2 /* Looking for message body lines */
133
b7520dd0
RC
134/* defines used for tag attributes */
135
136#define H_REQ 01
80765673
RC
137#define H_SAV 02
138#define H_HDR 04
139#define H_FND 010
b7520dd0
RC
140
141#define FROM_I headers[0].h_info
142#define SUBJECT_I headers[1].h_info
143#define INDEX &headers[2]
144#define INDEX_I headers[2].h_info
145#define DATE_I headers[3].h_info
146#define MSGID_I headers[4].h_info
147#define REPLYTO_I headers[5].h_info
982f965a
RC
148#define TO_I headers[6].h_info
149#define CC_I headers[7].h_info
150#define FIX headers[10]
b7520dd0
RC
151
152struct header {
153 char *h_tag;
154 int h_flags;
155 char *h_info;
156} headers[] = {
80765673 157 "From", H_REQ|H_SAV|H_HDR, 0,
982f965a 158 "Subject", H_REQ|H_SAV, 0,
b7520dd0 159 "Index", H_REQ|H_SAV, 0,
80765673
RC
160 "Date", H_SAV|H_HDR, 0,
161 "Message-Id", H_SAV|H_HDR, 0,
162 "Reply-To", H_SAV|H_HDR, 0,
80765673
RC
163 "To", H_SAV|H_HDR, 0,
164 "Cc", H_SAV|H_HDR, 0,
b7520dd0 165 "Description", H_REQ, 0,
4c01e0cf 166 "Repeat-By", 0, 0,
80765673 167 "Fix", 0, 0,
b7520dd0
RC
168 0, 0, 0,
169};
170
80765673
RC
171struct header *findheader();
172
b7520dd0
RC
173process()
174{
175 register struct header *hp;
176 register char *cp;
80765673 177 register int c;
b7520dd0 178 char *info;
80765673
RC
179 int state, tmp;
180 FILE *tfp, *fs;
b7520dd0
RC
181
182 /*
183 * Insure all headers are in a consistent
184 * state. Anything left there is free'd.
185 */
186 for (hp = headers; hp->h_tag; hp++) {
80765673 187 hp->h_flags &= ~H_FND;
b7520dd0 188 if (hp->h_info) {
80765673 189 free(hp->h_info);
b7520dd0
RC
190 hp->h_info = 0;
191 }
192 }
b7520dd0
RC
193 /*
194 * Read the report and make a copy. Must conform to RFC822 and
195 * be of the form... <tag>: <info>
80765673
RC
196 * Note that the input is expected to be in mh mail format
197 * (i.e., messages are separated by lines of ^A's).
b7520dd0 198 */
80765673
RC
199 while ((c = getchar()) == '\001' && peekc(stdin) == '\001')
200 while (getchar() != '\n')
201 ;
202 if (c == EOF)
203 return(0); /* all done */
204
b7520dd0 205 mktemp(tmpname);
80765673
RC
206 if ((tmp = creat(tmpname, msg_prot)) < 0) {
207 fprintf(stderr, "cannont create %s\n", tmpname);
208 exit(1);
209 }
210 if ((tfp = fdopen(tmp, "w")) == NULL) {
211 fprintf(stderr, "cannot fdopen temp file\n");
212 exit(1);
213 }
214
215 for (state = FLD; state != EOF && state != EOM; c = getchar()) {
216 switch (state) {
217 case FLD:
218 if (c == '\n' || c == '-')
219 goto body;
220 for (cp = buf; c != ':'; c = getchar()) {
221 if (cp < buf+sizeof(buf)-1 && c != '\n' && c != EOF) {
222 *cp++ = c;
223 continue;
224 }
225 *cp = '\0';
226 fputs(buf, tfp);
227 state = EOF;
228 while (c != EOF) {
229 if (c == '\n')
230 if ((tmp = peekc(stdin)) == EOF)
231 break;
232 else if (tmp == '\001') {
233 state = EOM;
234 break;
235 }
236 putc(c, tfp);
237 c = getchar();
238 }
239 fclose(tfp);
240 goto badfmt;
241 }
242 *cp = '\0';
243 fprintf(tfp, "%s:", buf);
244 hp = findheader(buf, state);
245
246 for (cp = buf; ; ) {
247 if (cp >= buf+sizeof(buf)-1) {
248 fprintf(stderr, "field truncated\n");
249 while ((c = getchar()) != EOF && c != '\n')
250 putc(c, tfp);
251 }
252 if ((c = getchar()) == EOF) {
253 state = EOF;
254 break;
255 }
256 putc(c, tfp);
257 *cp++ = c;
258 if (c == '\n')
259 if ((c = peekc(stdin)) != ' ' && c != '\t') {
260 if (c == EOF)
261 state = EOF;
262 else if (c == '\001')
263 state = EOM;
264 break;
265 }
266 }
267 *cp = '\0';
268 cp = buf;
269 break;
270
271 body:
272 state = BODY;
273 case BODY:
274 for (cp = buf; ; c = getchar()) {
275 if (c == EOF) {
276 state = EOF;
277 break;
278 }
279 if (c == '\001' && peekc(stdin) == '\001') {
280 state = EOM;
281 break;
282 }
283 putc(c, tfp);
284 *cp++ = c;
285 if (cp >= buf+sizeof(buf)-1 || c == '\n')
286 break;
287 }
288 *cp = '\0';
289 if ((cp = index(buf, ':')) == NULL)
290 continue;
291 *cp++ = '\0';
292 hp = findheader(buf, state);
b7520dd0 293 }
80765673
RC
294
295 /*
296 * Don't save the info if the header wasn't found, we don't
297 * care about the info, or the header is repeated.
298 */
299 if (hp == NULL || !(hp->h_flags & H_SAV) || hp->h_info)
300 continue;
b7520dd0
RC
301 while (isspace(*cp))
302 cp++;
303 if (*cp) {
304 info = cp;
305 while (*cp++);
306 cp--;
307 while (isspace(cp[-1]))
308 *--cp = '\0';
309 hp->h_info = (char *) malloc(strlen(info) + 1);
80765673
RC
310 if (hp->h_info == NULL) {
311 fprintf(stderr, "ran out of memory\n");
b7520dd0 312 continue;
80765673 313 }
b7520dd0
RC
314 strcpy(hp->h_info, info);
315 if (hp == INDEX)
316 chkindex(hp);
317 }
318 }
80765673 319 fclose(tfp);
b7520dd0
RC
320 /*
321 * Verify all the required pieces of information
322 * are present.
323 */
80765673 324 for (hp = headers; hp->h_tag; hp++) {
b7520dd0
RC
325 /*
326 * Mail the bug report back to the sender with a note
327 * explaining they must conform to the specification.
328 */
80765673
RC
329 if ((hp->h_flags & H_REQ) && !(hp->h_flags & H_FND)) {
330 if (debug)
331 printf("Missing %s\n", hp->h_tag);
332 badfmt:
333 reply(FROM_I, errfile, tmpname);
334 file(tmpname, "errors");
335 return(state == EOM);
336 }
b7520dd0 337 }
80765673
RC
338 /*
339 * Acknowledge receipt.
340 */
341 reply(FROM_I, ackfile, (char *)0);
342 file(tmpname, folder);
b7520dd0
RC
343 /*
344 * Append information about the new bug report
345 * to the summary file.
346 */
80765673 347 if ((fs = fopen(sumfile, "a")) == NULL)
b7520dd0 348 fprintf(stderr, "Can't open %s\n", sumfile);
80765673
RC
349 else {
350 fprintf(fs, "%14.14s/%-3d ", folder, num);
351 fprintf(fs, "%-51.51s Recv\n", INDEX_I);
352 fprintf(fs, "\t\t %-51.51s\n", SUBJECT_I);
b7520dd0 353 }
b7520dd0 354 fclose(fs);
ae422d11
SL
355 /*
356 * Check redistribution list and, if members,
357 * mail a copy of the bug report to these people.
358 */
359 redistribute(folder, num);
80765673
RC
360 return(state == EOM);
361}
362
363/*
364 * Lookup the string in the list of headers and return a pointer
365 * to the entry or NULL.
366 */
367
368struct header *
369findheader(name, state)
370 char *name;
371 int state;
372{
373 register struct header *hp;
374
375 if (debug)
376 printf("findheader(%s, %d)\n", name, state);
377
378 for (hp = headers; hp->h_tag; hp++) {
379 if (!streq(hp->h_tag, buf))
380 continue;
381 if ((hp->h_flags & H_HDR) && state != FLD)
382 continue;
383 hp->h_flags |= H_FND;
384 return(hp);
385 }
386 return(NULL);
b7520dd0
RC
387}
388
389/*
390 * Check the format of the Index information.
391 * A side effect is to set the name of the folder if all is well.
392 */
393
394chkindex(hp)
395 struct header *hp;
396{
80765673 397 register char *cp1, *cp2;
b7520dd0
RC
398 register char c;
399 struct stat stbuf;
400
401 if (debug)
80765673
RC
402 printf("chkindex(%s)\n", hp->h_info);
403 /*
647e1291 404 * Strip of leading "/", "usr/", or "src/".
80765673
RC
405 */
406 cp1 = hp->h_info;
407 while (*cp1 == '/')
408 cp1++;
647e1291 409 while (substr(cp1, "usr/") || substr(cp1, "src/"))
80765673 410 cp1 += 4;
b7520dd0
RC
411 /*
412 * Read the folder name and remove it from the index line.
413 */
80765673
RC
414 for (cp2 = folder; ;) {
415 switch (c = *cp1++) {
416 case '/':
417 if (cp2 == folder)
418 continue;
b7520dd0 419 break;
80765673
RC
420 case '\0':
421 cp1--;
422 break;
423 case ' ':
424 case '\t':
425 while (isspace(*cp1))
426 cp1++;
427 break;
428 default:
429 if (cp2 < folder+sizeof(folder)-1)
430 *cp2++ = c;
431 continue;
b7520dd0 432 }
80765673
RC
433 *cp2 = '\0';
434 for (cp2 = hp->h_info; *cp2++ = *cp1++; )
435 ;
436 break;
b7520dd0 437 }
80765673
RC
438 if (debug)
439 printf("folder = %s\n", folder);
b7520dd0
RC
440 /*
441 * Check to make sure we have a valid folder name
442 */
443 if (stat(folder, &stbuf) == 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR)
444 return;
445 /*
446 * The Index line is not in the correct format so clear
80765673 447 * the H_FND flag to mail back the correct format.
b7520dd0 448 */
80765673 449 hp->h_flags &= ~H_FND;
b7520dd0
RC
450}
451
452/*
453 * Move or copy the file msg to the folder (directory).
ae422d11
SL
454 * As a side effect, num is set to the number under which
455 * the message is filed in folder.
b7520dd0
RC
456 */
457
458file(fname, folder)
459 char *fname, *folder;
460{
461 register char *cp, n;
462 char msgname[MAXNAMLEN*2+2];
463 struct stat stbuf;
464 DIR *dirp;
465 struct direct *d;
466
467 if (debug)
80765673 468 printf("file(%s, %s)\n", fname, folder);
b7520dd0
RC
469 /*
470 * Get the next number to use by finding the last message number
471 * in folder and adding one.
472 */
473 if ((dirp = opendir(folder)) == NULL) {
474 fprintf(stderr, "Cannot open %s/%s\n", maildir, folder);
475 return;
476 }
477 num = 0;
478 while ((d = readdir(dirp)) != NULL) {
479 cp = d->d_name;
480 n = 0;
481 while (isdigit(*cp))
482 n = n * 10 + (*cp++ - '0');
483 if (*cp == '\0' && n > num)
484 num = n;
485 }
486 closedir(dirp);
487 num++;
488 /*
489 * Create the destination file "folder/num" and copy fname to it.
490 */
491 sprintf(msgname, "%s/%d", folder, num);
492 if (link(fname, msgname) < 0) {
493 int fin, fout;
494
80765673
RC
495 if ((fin = open(fname, 0)) < 0) {
496 fprintf(stderr, "cannot open %s\n", fname);
b7520dd0 497 return;
80765673
RC
498 }
499 if ((fout = creat(msgname, msg_prot)) < 0) {
500 fprintf(stderr, "cannot create %s\n", msgname);
b7520dd0 501 return;
80765673
RC
502 }
503 while ((n = read(fin, buf, sizeof(buf))) > 0)
504 write(fout, buf, n);
b7520dd0
RC
505 close(fin);
506 close(fout);
507 }
508 unlink(fname);
509}
510
ae422d11
SL
511/*
512 * Redistribute a bug report to those people indicated
513 * in the redistribution list file. Perhaps should also
514 * annotate bug report with this information for future
515 * reference?
516 */
517redistribute(folder, num)
518 char *folder;
519 int num;
520{
521 FILE *fredist, *fbug, *ftemp;
522 char line[BUFSIZ], bug[2 * MAXNAMLEN + 1];
523 register char *cp;
524 int redistcnt, continuation, first;
525
526 fredist = fopen(redistfile, "r");
527 if (fredist == NULL) {
528 if (debug)
529 printf("redistribute(%s, %d), no distribution list\n",
530 folder, num);
531 return;
532 }
533 continuation = 0;
534 first = 1;
535 redistcnt = 0;
536 while (fgets(line, sizeof (line) - 1, fredist) != NULL) {
537 if (debug)
538 printf("%s: %s", redistfile, line);
539 if (continuation && index(line, '\\'))
540 continue;
541 continuation = 0;
542 cp = any(line, " \t");
543 if (cp == NULL)
544 continue;
545 *cp++ = '\0';
546 if (strcmp(folder, line) == 0)
547 goto found;
548 if (index(cp, '\\'))
549 continuation = 1;
550 }
551 if (debug)
552 printf("no redistribution list found\n");
553 fclose(fredist);
554 return;
555found:
556 mktemp(disttmp);
557 ftemp = fopen(disttmp, "w+r");
558 if (ftemp == NULL) {
559 if (debug)
560 printf("%s: couldn't create\n", disttmp);
561 return;
562 }
563again:
564 if (debug)
565 printf("redistribution list %s", cp);
566 while (cp) {
567 char *user, terminator;
568
569 while (*cp && (*cp == ' ' || *cp == '\t' || *cp == ','))
570 cp++;
571 user = cp, cp = any(cp, ", \t\n\\");
572 if (cp) {
573 terminator = *cp;
574 *cp++ = '\0';
575 if (terminator == '\n')
576 cp = 0;
577 if (terminator == '\\')
578 continuation++;
579 }
580 if (*user == '\0')
581 continue;
582 if (debug)
583 printf("copy to %s\n", user);
584 if (first) {
585 fprintf(ftemp, "To: %s", user);
586 first = 0;
587 } else
588 fprintf(ftemp, ", %s", user);
589 redistcnt++;
590 }
591 if (!first)
592 putc('\n', ftemp);
593 if (continuation) {
594 first = 1;
595 continuation = 0;
596 cp = line;
597 if (fgets(line, sizeof (line) - 1, fredist))
598 goto again;
599 }
600 fclose(fredist);
601 if (redistcnt == 0)
602 goto cleanup;
603 fprintf(ftemp, "Subject: ");
604 if (SUBJECT_I)
605 fprintf(ftemp, "%s\n", SUBJECT_I);
606 else
607 fprintf(ftemp, "Untitled bug report\n");
608 fprintf(ftemp, "\nRedistributed-by: %s%s\n", BUGS_NAME, BUGS_HOME);
609 /*
610 * Create copy of bug report. Perhaps we should
611 * truncate large messages and just give people
612 * a pointer to the original?
613 */
614 sprintf(bug, "%s/%d", folder, num);
615 fbug = fopen(bug, "r");
616 if (fbug == NULL) {
617 if (debug)
618 printf("%s: disappeared?\n", bug);
619 goto cleanup;
620 }
621 first = 1;
622 while (fgets(line, sizeof (line) - 1, fbug)) {
623 /* first blank line indicates start of mesg */
624 if (first && line[0] == '\n') {
625 first = 0;
626 continue;
627 }
628 fputs(line, ftemp);
629 }
630 fclose(fbug);
631 if (first) {
632 if (debug)
633 printf("empty bug report?\n");
634 goto cleanup;
635 }
636 if (dodeliver(ftemp))
637 unlink(disttmp);
638 fclose(ftemp);
639 return;
640cleanup:
641 fclose(ftemp);
642 unlink(disttmp);
643}
644
645dodeliver(fd)
646 FILE *fd;
647{
648 char buf[BUFSIZ], cmd[BUFSIZ];
649 FILE *pf, *popen();
650
651 strcpy(cmd, MAILCMD);
652 if (debug) {
653 strcat(cmd, " -v");
654 printf("dodeliver \"%s\"\n", cmd);
655 }
656 pf = popen(cmd, "w");
657 if (pf == NULL) {
658 if (debug)
659 printf("dodeliver, \"%s\" failed\n", cmd);
660 return (0);
661 }
662 rewind(fd);
663 while (fgets(buf, sizeof (buf) - 1, fd)) {
664 if (debug)
665 printf("%s", buf);
666 (void) fputs(buf, pf);
667 }
668 if (debug)
669 printf("EOF\n");
670 (void) pclose(pf);
671 return (1);
672}
673
b7520dd0
RC
674/*
675 * Mail file1 and file2 back to the sender.
676 */
677
678reply(to, file1, file2)
679 char *to, *file1, *file2;
680{
ae422d11 681 int pfd[2], in, w;
b7520dd0
RC
682 FILE *fout;
683
684 if (debug)
80765673
RC
685 printf("reply(%s, %s, %s)\n", to, file1, file2);
686
b7520dd0
RC
687 /*
688 * Create a temporary file to put the message in.
689 */
690 mktemp(draft);
ae422d11 691 if ((fout = fopen(draft, "w+r")) == NULL) {
b7520dd0
RC
692 fprintf(stderr, "Can't create %s\n", draft);
693 return;
694 }
695 /*
696 * Output the proper header information.
697 */
ae422d11 698 fprintf(fout, "Reply-To: %s%s\n", BUGS_NAME, BUGS_HOME);
aef45c03 699 fprintf(fout, "From: %s%s (Bugs Bunny)\n", BUGS_NAME, BUGS_HOME);
b7520dd0
RC
700 if (REPLYTO_I != NULL)
701 to = REPLYTO_I;
702 if ((to = fixaddr(to)) == 0) {
703 fprintf(stderr, "No one to reply to\n");
704 return;
705 }
706 fprintf(fout, "To: %s\n", to);
707 if (SUBJECT_I) {
708 fprintf(fout, "Subject: ");
709 if ((SUBJECT_I[0] != 'R' && SUBJECT_I[0] != 'r') ||
710 (SUBJECT_I[1] != 'E' && SUBJECT_I[1] != 'e') ||
711 SUBJECT_I[2] != ':')
712 fprintf(fout, "Re: ");
713 fprintf(fout, "%s\n", SUBJECT_I);
714 }
715 if (DATE_I) {
716 fprintf(fout, "In-Acknowledgement-Of: Your message of ");
717 fprintf(fout, "%s.\n", DATE_I);
718 if (MSGID_I)
719 fprintf(fout, " %s\n", MSGID_I);
720 }
ae422d11 721 fprintf(fout, "\n");
b7520dd0 722 if ((in = open(file1, 0)) >= 0) {
80765673
RC
723 while ((w = read(in, buf, sizeof(buf))) > 0)
724 fwrite(buf, 1, w, fout);
b7520dd0
RC
725 close(in);
726 }
727 if (file2 && (in = open(file2, 0)) >= 0) {
80765673
RC
728 while ((w = read(in, buf, sizeof(buf))) > 0)
729 fwrite(buf, 1, w, fout);
b7520dd0
RC
730 close(in);
731 }
ae422d11 732 if (dodeliver(fout))
b7520dd0 733 unlink(draft);
ae422d11 734 fclose(fout);
b7520dd0
RC
735}
736
737/*
738 * fix names like "xxx (something)" to "xxx" and
739 * "xxx <something>" to "something".
740 */
741
742char *
743fixaddr(text)
744 char *text;
745{
746 register char *cp, *lp, c;
747 char *tp;
748
749 if (!text)
750 return(0);
751 for (lp = cp = text; ; ) {
752 switch (c = *cp++) {
753 case '(':
754 while (*cp && *cp++ != ')');
755 continue;
756 case '<':
757 lp = text;
758 case '>':
759 continue;
760 case '\0':
761 while (lp != text && (*lp == ' ' || *lp == '\t'))
762 lp--;
763 *lp = c;
764 return(text);
765 }
766 *lp++ = c;
767 }
768}
769
770/*
771 * Compare two strings and convert any upper case letters to lower case.
772 */
773
80765673
RC
774streq(s1, s2)
775 register char *s1, *s2;
b7520dd0
RC
776{
777 register int c;
778
80765673
RC
779 while (c = *s1++)
780 if ((c | 040) != (*s2++ | 040))
b7520dd0 781 return(0);
80765673
RC
782 return(*s2 == '\0');
783}
784
785/*
786 * Return true if string s2 matches the first part of s1.
787 */
788
789substr(s1, s2)
790 register char *s1, *s2;
791{
792 register int c;
793
794 while (c = *s2++)
795 if (c != *s1++)
796 return(0);
797 return(1);
798}
799
ae422d11
SL
800char *
801any(cp, set)
802 register char *cp;
803 char *set;
804{
805 register char *sp;
806
807 if (cp == 0 || set == 0)
808 return (0);
809 while (*cp) {
810 for (sp = set; *sp; sp++)
811 if (*cp == *sp)
812 return (cp);
813 cp++;
814 }
815 return ((char *)0);
816}
817
80765673
RC
818peekc(fp)
819FILE *fp;
820{
821 register c;
822
823 c = getc(fp);
824 ungetc(c, fp);
825 return(c);
b7520dd0 826}