1*12695Sralph /* bugfiler.c 4.2 83/05/23 */ 212375Sralph /* 312375Sralph * Bug report processing program. 412375Sralph * It is designed to be invoked by alias(5) and to be compatible with mh. 512375Sralph */ 612375Sralph 712375Sralph #include <stdio.h> 812375Sralph #include <ctype.h> 912375Sralph #include <signal.h> 1012375Sralph #include <sys/types.h> 1112375Sralph #include <sys/stat.h> 12*12695Sralph #include <sys/dir.h> 1312375Sralph 1412375Sralph char deliver[] = "/usr/local/lib/mh/deliver"; 1512375Sralph char unixtomh[] = "/usr/local/lib/mh/unixtomh"; 1612375Sralph char *maildir = "/ra/bugs/mail"; 1712375Sralph char ackfile[] = ".ack"; 1812375Sralph char errfile[] = ".format"; 1912375Sralph char sumfile[] = "summary"; 2012375Sralph char logfile[] = "errors/log"; 2112375Sralph char tmpname[] = "BfXXXXXX"; 2212375Sralph char draft[] = "RpXXXXXX"; 2312375Sralph 24*12695Sralph char buf[8192]; 2512375Sralph char folder[MAXNAMLEN]; 2612375Sralph int num; 2712375Sralph int msg_prot = 0664; 2812375Sralph 2912375Sralph int debug; 3012375Sralph 3112375Sralph char *index(); 3212375Sralph char *rindex(); 3312375Sralph char *fixaddr(); 3412375Sralph 3512375Sralph main(argc, argv) 3612375Sralph char *argv[]; 3712375Sralph { 3812375Sralph register char *cp; 39*12695Sralph register int n; 40*12695Sralph int pfd[2]; 4112375Sralph 4212375Sralph if (argc > 3) { 4312375Sralph usage: 44*12695Sralph fprintf(stderr, "Usage: bugfiler [-d] [-mmsg_mode] [maildir]\n"); 4512375Sralph exit(1); 4612375Sralph } 4712375Sralph while (--argc > 0) { 4812375Sralph cp = *++argv; 49*12695Sralph if (*cp == '-') 50*12695Sralph switch (cp[1]) { 5112375Sralph case 'd': 5212375Sralph debug++; 5312375Sralph break; 54*12695Sralph 55*12695Sralph case 'm': /* set message protection */ 56*12695Sralph n = 0; 57*12695Sralph for (cp += 2; *cp >= '0' && *cp <= '7'; ) 58*12695Sralph n = (n << 3) + (*cp++ - '0'); 59*12695Sralph msg_prot = n & 0777; 60*12695Sralph break; 61*12695Sralph 6212375Sralph default: 6312375Sralph goto usage; 6412375Sralph } 6512375Sralph else 6612375Sralph maildir = cp; 6712375Sralph } 68*12695Sralph if (!debug) 69*12695Sralph freopen(logfile, "a", stderr); 70*12695Sralph 7112375Sralph if (chdir(maildir) < 0) { 7212375Sralph fprintf(stderr, "can't chdir to %s\n", maildir); 7312375Sralph exit(1); 7412375Sralph } 75*12695Sralph umask(0); 76*12695Sralph 77*12695Sralph #ifdef UNIXCOMP 78*12695Sralph /* 79*12695Sralph * Convert UNIX style mail to mh style by filtering stdin through 80*12695Sralph * unixtomh. 81*12695Sralph */ 82*12695Sralph if (pipe(pfd) >= 0) { 83*12695Sralph while ((n = fork()) == -1) 84*12695Sralph sleep(5); 85*12695Sralph if (n == 0) { 86*12695Sralph close(pfd[0]); 87*12695Sralph dup2(pfd[1], 1); 88*12695Sralph close(pfd[1]); 89*12695Sralph execl(unixtomh, "unixtomh", 0); 90*12695Sralph _exit(127); 91*12695Sralph } 92*12695Sralph close(pfd[1]); 93*12695Sralph dup2(pfd[0], 0); 94*12695Sralph close(pfd[0]); 95*12695Sralph } 96*12695Sralph #endif 97*12695Sralph while (process()) 98*12695Sralph ; 99*12695Sralph exit(0); 10012375Sralph } 10112375Sralph 102*12695Sralph /* states */ 103*12695Sralph 104*12695Sralph #define EOM 0 /* End of message seen */ 105*12695Sralph #define FLD 1 /* Looking for header lines */ 106*12695Sralph #define BODY 2 /* Looking for message body lines */ 107*12695Sralph 10812375Sralph /* defines used for tag attributes */ 10912375Sralph 11012375Sralph #define H_REQ 01 111*12695Sralph #define H_SAV 02 112*12695Sralph #define H_HDR 04 113*12695Sralph #define H_FND 010 11412375Sralph 11512375Sralph #define FROM_I headers[0].h_info 11612375Sralph #define SUBJECT_I headers[1].h_info 11712375Sralph #define INDEX &headers[2] 11812375Sralph #define INDEX_I headers[2].h_info 11912375Sralph #define DATE_I headers[3].h_info 12012375Sralph #define MSGID_I headers[4].h_info 12112375Sralph #define REPLYTO_I headers[5].h_info 12212375Sralph #define RETURNPATH_I headers[6].h_info 12312375Sralph #define TO_I headers[7].h_info 12412375Sralph #define CC_I headers[8].h_info 12512375Sralph #define FIX headers[11] 12612375Sralph 12712375Sralph struct header { 12812375Sralph char *h_tag; 12912375Sralph int h_flags; 13012375Sralph char *h_info; 13112375Sralph } headers[] = { 132*12695Sralph "From", H_REQ|H_SAV|H_HDR, 0, 133*12695Sralph "Subject", H_REQ|H_SAV|H_HDR, 0, 13412375Sralph "Index", H_REQ|H_SAV, 0, 135*12695Sralph "Date", H_SAV|H_HDR, 0, 136*12695Sralph "Message-Id", H_SAV|H_HDR, 0, 137*12695Sralph "Reply-To", H_SAV|H_HDR, 0, 138*12695Sralph "Return-Path", H_SAV|H_HDR, 0, 139*12695Sralph "To", H_SAV|H_HDR, 0, 140*12695Sralph "Cc", H_SAV|H_HDR, 0, 14112375Sralph "Description", H_REQ, 0, 14212375Sralph "Repeat-By", H_REQ, 0, 143*12695Sralph "Fix", 0, 0, 14412375Sralph 0, 0, 0, 14512375Sralph }; 14612375Sralph 147*12695Sralph struct header *findheader(); 148*12695Sralph 14912375Sralph process() 15012375Sralph { 15112375Sralph register struct header *hp; 15212375Sralph register char *cp; 153*12695Sralph register int c; 15412375Sralph char *info; 155*12695Sralph int state, tmp; 156*12695Sralph FILE *tfp, *fs; 15712375Sralph 15812375Sralph /* 15912375Sralph * Insure all headers are in a consistent 16012375Sralph * state. Anything left there is free'd. 16112375Sralph */ 16212375Sralph for (hp = headers; hp->h_tag; hp++) { 163*12695Sralph hp->h_flags &= ~H_FND; 16412375Sralph if (hp->h_info) { 165*12695Sralph free(hp->h_info); 16612375Sralph hp->h_info = 0; 16712375Sralph } 16812375Sralph } 16912375Sralph /* 17012375Sralph * Read the report and make a copy. Must conform to RFC822 and 17112375Sralph * be of the form... <tag>: <info> 172*12695Sralph * Note that the input is expected to be in mh mail format 173*12695Sralph * (i.e., messages are separated by lines of ^A's). 17412375Sralph */ 175*12695Sralph while ((c = getchar()) == '\001' && peekc(stdin) == '\001') 176*12695Sralph while (getchar() != '\n') 177*12695Sralph ; 178*12695Sralph if (c == EOF) 179*12695Sralph return(0); /* all done */ 180*12695Sralph 18112375Sralph mktemp(tmpname); 182*12695Sralph if ((tmp = creat(tmpname, msg_prot)) < 0) { 183*12695Sralph fprintf(stderr, "cannont create %s\n", tmpname); 184*12695Sralph exit(1); 185*12695Sralph } 186*12695Sralph if ((tfp = fdopen(tmp, "w")) == NULL) { 187*12695Sralph fprintf(stderr, "cannot fdopen temp file\n"); 188*12695Sralph exit(1); 189*12695Sralph } 190*12695Sralph 191*12695Sralph for (state = FLD; state != EOF && state != EOM; c = getchar()) { 192*12695Sralph switch (state) { 193*12695Sralph case FLD: 194*12695Sralph if (c == '\n' || c == '-') 195*12695Sralph goto body; 196*12695Sralph for (cp = buf; c != ':'; c = getchar()) { 197*12695Sralph if (cp < buf+sizeof(buf)-1 && c != '\n' && c != EOF) { 198*12695Sralph *cp++ = c; 199*12695Sralph continue; 200*12695Sralph } 201*12695Sralph *cp = '\0'; 202*12695Sralph fputs(buf, tfp); 203*12695Sralph state = EOF; 204*12695Sralph while (c != EOF) { 205*12695Sralph if (c == '\n') 206*12695Sralph if ((tmp = peekc(stdin)) == EOF) 207*12695Sralph break; 208*12695Sralph else if (tmp == '\001') { 209*12695Sralph state = EOM; 210*12695Sralph break; 211*12695Sralph } 212*12695Sralph putc(c, tfp); 213*12695Sralph c = getchar(); 214*12695Sralph } 215*12695Sralph fclose(tfp); 216*12695Sralph goto badfmt; 217*12695Sralph } 218*12695Sralph *cp = '\0'; 219*12695Sralph fprintf(tfp, "%s:", buf); 220*12695Sralph hp = findheader(buf, state); 221*12695Sralph 222*12695Sralph for (cp = buf; ; ) { 223*12695Sralph if (cp >= buf+sizeof(buf)-1) { 224*12695Sralph fprintf(stderr, "field truncated\n"); 225*12695Sralph while ((c = getchar()) != EOF && c != '\n') 226*12695Sralph putc(c, tfp); 227*12695Sralph } 228*12695Sralph if ((c = getchar()) == EOF) { 229*12695Sralph state = EOF; 230*12695Sralph break; 231*12695Sralph } 232*12695Sralph putc(c, tfp); 233*12695Sralph *cp++ = c; 234*12695Sralph if (c == '\n') 235*12695Sralph if ((c = peekc(stdin)) != ' ' && c != '\t') { 236*12695Sralph if (c == EOF) 237*12695Sralph state = EOF; 238*12695Sralph else if (c == '\001') 239*12695Sralph state = EOM; 240*12695Sralph break; 241*12695Sralph } 242*12695Sralph } 243*12695Sralph *cp = '\0'; 244*12695Sralph cp = buf; 245*12695Sralph break; 246*12695Sralph 247*12695Sralph body: 248*12695Sralph state = BODY; 249*12695Sralph case BODY: 250*12695Sralph for (cp = buf; ; c = getchar()) { 251*12695Sralph if (c == EOF) { 252*12695Sralph state = EOF; 253*12695Sralph break; 254*12695Sralph } 255*12695Sralph if (c == '\001' && peekc(stdin) == '\001') { 256*12695Sralph state = EOM; 257*12695Sralph break; 258*12695Sralph } 259*12695Sralph putc(c, tfp); 260*12695Sralph *cp++ = c; 261*12695Sralph if (cp >= buf+sizeof(buf)-1 || c == '\n') 262*12695Sralph break; 263*12695Sralph } 264*12695Sralph *cp = '\0'; 265*12695Sralph if ((cp = index(buf, ':')) == NULL) 266*12695Sralph continue; 267*12695Sralph *cp++ = '\0'; 268*12695Sralph hp = findheader(buf, state); 269*12695Sralph } 270*12695Sralph 271*12695Sralph /* 272*12695Sralph * Don't save the info if the header wasn't found, we don't 273*12695Sralph * care about the info, or the header is repeated. 274*12695Sralph */ 275*12695Sralph if (hp == NULL || !(hp->h_flags & H_SAV) || hp->h_info) 27612375Sralph continue; 27712375Sralph while (isspace(*cp)) 27812375Sralph cp++; 27912375Sralph if (*cp) { 28012375Sralph info = cp; 28112375Sralph while (*cp++); 28212375Sralph cp--; 28312375Sralph while (isspace(cp[-1])) 28412375Sralph *--cp = '\0'; 28512375Sralph hp->h_info = (char *) malloc(strlen(info) + 1); 286*12695Sralph if (hp->h_info == NULL) { 287*12695Sralph fprintf(stderr, "ran out of memory\n"); 28812375Sralph continue; 289*12695Sralph } 29012375Sralph strcpy(hp->h_info, info); 29112375Sralph if (hp == INDEX) 29212375Sralph chkindex(hp); 29312375Sralph } 29412375Sralph } 295*12695Sralph fclose(tfp); 29612375Sralph /* 29712375Sralph * Verify all the required pieces of information 29812375Sralph * are present. 29912375Sralph */ 300*12695Sralph for (hp = headers; hp->h_tag; hp++) { 30112375Sralph /* 30212375Sralph * Mail the bug report back to the sender with a note 30312375Sralph * explaining they must conform to the specification. 30412375Sralph */ 305*12695Sralph if ((hp->h_flags & H_REQ) && !(hp->h_flags & H_FND)) { 306*12695Sralph if (debug) 307*12695Sralph printf("Missing %s\n", hp->h_tag); 308*12695Sralph badfmt: 309*12695Sralph reply(FROM_I, errfile, tmpname); 310*12695Sralph file(tmpname, "errors"); 311*12695Sralph return(state == EOM); 312*12695Sralph } 31312375Sralph } 31412375Sralph /* 315*12695Sralph * Acknowledge receipt. 316*12695Sralph */ 317*12695Sralph reply(FROM_I, ackfile, (char *)0); 318*12695Sralph file(tmpname, folder); 319*12695Sralph /* 32012375Sralph * Append information about the new bug report 32112375Sralph * to the summary file. 32212375Sralph */ 323*12695Sralph if ((fs = fopen(sumfile, "a")) == NULL) 32412375Sralph fprintf(stderr, "Can't open %s\n", sumfile); 325*12695Sralph else { 326*12695Sralph fprintf(fs, "%14.14s/%-3d ", folder, num); 327*12695Sralph fprintf(fs, "%-51.51s Recv\n", INDEX_I); 328*12695Sralph fprintf(fs, "\t\t %-51.51s\n", SUBJECT_I); 32912375Sralph } 33012375Sralph fclose(fs); 331*12695Sralph return(state == EOM); 33212375Sralph } 33312375Sralph 33412375Sralph /* 335*12695Sralph * Lookup the string in the list of headers and return a pointer 336*12695Sralph * to the entry or NULL. 337*12695Sralph */ 338*12695Sralph 339*12695Sralph struct header * 340*12695Sralph findheader(name, state) 341*12695Sralph char *name; 342*12695Sralph int state; 343*12695Sralph { 344*12695Sralph register struct header *hp; 345*12695Sralph 346*12695Sralph if (debug) 347*12695Sralph printf("findheader(%s, %d)\n", name, state); 348*12695Sralph 349*12695Sralph for (hp = headers; hp->h_tag; hp++) { 350*12695Sralph if (!streq(hp->h_tag, buf)) 351*12695Sralph continue; 352*12695Sralph if ((hp->h_flags & H_HDR) && state != FLD) 353*12695Sralph continue; 354*12695Sralph hp->h_flags |= H_FND; 355*12695Sralph return(hp); 356*12695Sralph } 357*12695Sralph return(NULL); 358*12695Sralph } 359*12695Sralph 360*12695Sralph /* 36112375Sralph * Check the format of the Index information. 36212375Sralph * A side effect is to set the name of the folder if all is well. 36312375Sralph */ 36412375Sralph 36512375Sralph chkindex(hp) 36612375Sralph struct header *hp; 36712375Sralph { 368*12695Sralph register char *cp1, *cp2; 36912375Sralph register char c; 37012375Sralph struct stat stbuf; 37112375Sralph 37212375Sralph if (debug) 373*12695Sralph printf("chkindex(%s)\n", hp->h_info); 37412375Sralph /* 375*12695Sralph * Strip of leading "/", "usr/", "src/" or "sys/". 376*12695Sralph */ 377*12695Sralph cp1 = hp->h_info; 378*12695Sralph while (*cp1 == '/') 379*12695Sralph cp1++; 380*12695Sralph while (substr(cp1, "usr/") || substr(cp1, "src/") || substr(cp1, "sys/")) 381*12695Sralph cp1 += 4; 382*12695Sralph /* 38312375Sralph * Read the folder name and remove it from the index line. 38412375Sralph */ 385*12695Sralph for (cp2 = folder; ;) { 386*12695Sralph switch (c = *cp1++) { 387*12695Sralph case '/': 388*12695Sralph if (cp2 == folder) 389*12695Sralph continue; 39012375Sralph break; 391*12695Sralph case '\0': 392*12695Sralph cp1--; 393*12695Sralph break; 394*12695Sralph case ' ': 395*12695Sralph case '\t': 396*12695Sralph while (isspace(*cp1)) 397*12695Sralph cp1++; 398*12695Sralph break; 399*12695Sralph default: 400*12695Sralph if (cp2 < folder+sizeof(folder)-1) 401*12695Sralph *cp2++ = c; 402*12695Sralph continue; 40312375Sralph } 404*12695Sralph *cp2 = '\0'; 405*12695Sralph for (cp2 = hp->h_info; *cp2++ = *cp1++; ) 406*12695Sralph ; 407*12695Sralph break; 40812375Sralph } 409*12695Sralph if (debug) 410*12695Sralph printf("folder = %s\n", folder); 41112375Sralph /* 41212375Sralph * Check to make sure we have a valid folder name 41312375Sralph */ 41412375Sralph if (stat(folder, &stbuf) == 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR) 41512375Sralph return; 41612375Sralph /* 41712375Sralph * The Index line is not in the correct format so clear 418*12695Sralph * the H_FND flag to mail back the correct format. 41912375Sralph */ 420*12695Sralph hp->h_flags &= ~H_FND; 42112375Sralph } 42212375Sralph 42312375Sralph /* 42412375Sralph * Move or copy the file msg to the folder (directory). 42512375Sralph * A side effect is to set num to the number of the file in folder. 42612375Sralph */ 42712375Sralph 42812375Sralph file(fname, folder) 42912375Sralph char *fname, *folder; 43012375Sralph { 43112375Sralph register char *cp, n; 43212375Sralph char msgname[MAXNAMLEN*2+2]; 43312375Sralph struct stat stbuf; 43412375Sralph DIR *dirp; 43512375Sralph struct direct *d; 43612375Sralph 43712375Sralph if (debug) 438*12695Sralph printf("file(%s, %s)\n", fname, folder); 43912375Sralph /* 44012375Sralph * Get the next number to use by finding the last message number 44112375Sralph * in folder and adding one. 44212375Sralph */ 44312375Sralph if ((dirp = opendir(folder)) == NULL) { 44412375Sralph fprintf(stderr, "Cannot open %s/%s\n", maildir, folder); 44512375Sralph return; 44612375Sralph } 44712375Sralph num = 0; 44812375Sralph while ((d = readdir(dirp)) != NULL) { 44912375Sralph cp = d->d_name; 45012375Sralph n = 0; 45112375Sralph while (isdigit(*cp)) 45212375Sralph n = n * 10 + (*cp++ - '0'); 45312375Sralph if (*cp == '\0' && n > num) 45412375Sralph num = n; 45512375Sralph } 45612375Sralph closedir(dirp); 45712375Sralph num++; 45812375Sralph /* 45912375Sralph * Create the destination file "folder/num" and copy fname to it. 46012375Sralph */ 46112375Sralph sprintf(msgname, "%s/%d", folder, num); 46212375Sralph if (link(fname, msgname) < 0) { 46312375Sralph int fin, fout; 46412375Sralph 465*12695Sralph if ((fin = open(fname, 0)) < 0) { 466*12695Sralph fprintf(stderr, "cannot open %s\n", fname); 46712375Sralph return; 468*12695Sralph } 469*12695Sralph if ((fout = creat(msgname, msg_prot)) < 0) { 470*12695Sralph fprintf(stderr, "cannot create %s\n", msgname); 47112375Sralph return; 472*12695Sralph } 473*12695Sralph while ((n = read(fin, buf, sizeof(buf))) > 0) 474*12695Sralph write(fout, buf, n); 47512375Sralph close(fin); 47612375Sralph close(fout); 47712375Sralph } 47812375Sralph unlink(fname); 47912375Sralph } 48012375Sralph 48112375Sralph /* 48212375Sralph * Mail file1 and file2 back to the sender. 48312375Sralph */ 48412375Sralph 48512375Sralph reply(to, file1, file2) 48612375Sralph char *to, *file1, *file2; 48712375Sralph { 48812375Sralph int (*istat)(), (*qstat)(); 48912375Sralph int pid, w, status, pfd[2], in; 49012375Sralph FILE *fout; 49112375Sralph 49212375Sralph if (debug) 493*12695Sralph printf("reply(%s, %s, %s)\n", to, file1, file2); 494*12695Sralph 49512375Sralph /* 49612375Sralph * Create a temporary file to put the message in. 49712375Sralph */ 49812375Sralph mktemp(draft); 49912375Sralph if ((fout = fopen(draft, "w")) == NULL) { 50012375Sralph fprintf(stderr, "Can't create %s\n", draft); 50112375Sralph return; 50212375Sralph } 50312375Sralph /* 50412375Sralph * Output the proper header information. 50512375Sralph */ 506*12695Sralph fprintf(fout, "Reply-To: 4bsd-bugs%ucbarpa@BERKELEY\n"); 50712375Sralph if (RETURNPATH_I != NULL) 50812375Sralph to = RETURNPATH_I; 50912375Sralph if (REPLYTO_I != NULL) 51012375Sralph to = REPLYTO_I; 51112375Sralph if ((to = fixaddr(to)) == 0) { 51212375Sralph fprintf(stderr, "No one to reply to\n"); 51312375Sralph return; 51412375Sralph } 51512375Sralph fprintf(fout, "To: %s\n", to); 51612375Sralph if (SUBJECT_I) { 51712375Sralph fprintf(fout, "Subject: "); 51812375Sralph if ((SUBJECT_I[0] != 'R' && SUBJECT_I[0] != 'r') || 51912375Sralph (SUBJECT_I[1] != 'E' && SUBJECT_I[1] != 'e') || 52012375Sralph SUBJECT_I[2] != ':') 52112375Sralph fprintf(fout, "Re: "); 52212375Sralph fprintf(fout, "%s\n", SUBJECT_I); 52312375Sralph } 52412375Sralph if (DATE_I) { 52512375Sralph fprintf(fout, "In-Acknowledgement-Of: Your message of "); 52612375Sralph fprintf(fout, "%s.\n", DATE_I); 52712375Sralph if (MSGID_I) 52812375Sralph fprintf(fout, " %s\n", MSGID_I); 52912375Sralph } 53012375Sralph fprintf(fout, "----------\n"); 53112375Sralph if ((in = open(file1, 0)) >= 0) { 532*12695Sralph while ((w = read(in, buf, sizeof(buf))) > 0) 533*12695Sralph fwrite(buf, 1, w, fout); 53412375Sralph close(in); 53512375Sralph } 53612375Sralph if (file2 && (in = open(file2, 0)) >= 0) { 537*12695Sralph while ((w = read(in, buf, sizeof(buf))) > 0) 538*12695Sralph fwrite(buf, 1, w, fout); 53912375Sralph close(in); 54012375Sralph } 54112375Sralph fclose(fout); 54212375Sralph while ((pid = fork()) == -1) 54312375Sralph sleep(5); 54412375Sralph if (pid == 0) { 54512375Sralph execl(deliver, "deliver", draft, 0); 54612375Sralph _exit(127); 54712375Sralph } 54812375Sralph istat = signal(SIGINT, SIG_IGN); 54912375Sralph qstat = signal(SIGQUIT, SIG_IGN); 55012375Sralph while ((w = wait(&status)) != -1 && w != pid); 55112375Sralph signal(SIGINT, istat); 55212375Sralph signal(SIGQUIT, qstat); 55312375Sralph if (w != -1 && status == 0) 55412375Sralph unlink(draft); 55512375Sralph } 55612375Sralph 55712375Sralph /* 55812375Sralph * fix names like "xxx (something)" to "xxx" and 55912375Sralph * "xxx <something>" to "something". 56012375Sralph */ 56112375Sralph 56212375Sralph char * 56312375Sralph fixaddr(text) 56412375Sralph char *text; 56512375Sralph { 56612375Sralph register char *cp, *lp, c; 56712375Sralph char *tp; 56812375Sralph 56912375Sralph if (!text) 57012375Sralph return(0); 57112375Sralph for (lp = cp = text; ; ) { 57212375Sralph switch (c = *cp++) { 57312375Sralph case '(': 57412375Sralph while (*cp && *cp++ != ')'); 57512375Sralph continue; 57612375Sralph case '<': 57712375Sralph lp = text; 57812375Sralph case '>': 57912375Sralph continue; 58012375Sralph case '\0': 58112375Sralph while (lp != text && (*lp == ' ' || *lp == '\t')) 58212375Sralph lp--; 58312375Sralph *lp = c; 58412375Sralph return(text); 58512375Sralph } 58612375Sralph *lp++ = c; 58712375Sralph } 58812375Sralph } 58912375Sralph 59012375Sralph /* 59112375Sralph * Compare two strings and convert any upper case letters to lower case. 59212375Sralph */ 59312375Sralph 594*12695Sralph streq(s1, s2) 595*12695Sralph register char *s1, *s2; 59612375Sralph { 59712375Sralph register int c; 59812375Sralph 599*12695Sralph while (c = *s1++) 600*12695Sralph if ((c | 040) != (*s2++ | 040)) 60112375Sralph return(0); 602*12695Sralph return(*s2 == '\0'); 60312375Sralph } 604*12695Sralph 605*12695Sralph /* 606*12695Sralph * Return true if string s2 matches the first part of s1. 607*12695Sralph */ 608*12695Sralph 609*12695Sralph substr(s1, s2) 610*12695Sralph register char *s1, *s2; 611*12695Sralph { 612*12695Sralph register int c; 613*12695Sralph 614*12695Sralph while (c = *s2++) 615*12695Sralph if (c != *s1++) 616*12695Sralph return(0); 617*12695Sralph return(1); 618*12695Sralph } 619*12695Sralph 620*12695Sralph peekc(fp) 621*12695Sralph FILE *fp; 622*12695Sralph { 623*12695Sralph register c; 624*12695Sralph 625*12695Sralph c = getc(fp); 626*12695Sralph ungetc(c, fp); 627*12695Sralph return(c); 628*12695Sralph } 629