Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
bee79b64 KB |
2 | * Copyright (c) 1988 Regents of the University of California. |
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. | |
11 | * | |
12 | * Sendmail | |
13 | * Copyright (c) 1983 Eric P. Allman | |
14 | * Berkeley, California | |
15 | */ | |
b2a81223 DF |
16 | |
17 | #ifndef lint | |
e3419641 | 18 | static char sccsid[] = "@(#)util.c 5.14 (Berkeley) 12/5/88"; |
bee79b64 | 19 | #endif /* not lint */ |
b2a81223 | 20 | |
d6a28dd8 | 21 | # include <stdio.h> |
f6a0cc15 EA |
22 | # include <sys/types.h> |
23 | # include <sys/stat.h> | |
b3cbe40f | 24 | # include <sysexits.h> |
5c373723 | 25 | # include <errno.h> |
5c373723 | 26 | # include "sendmail.h" |
b3cbe40f EA |
27 | |
28 | /* | |
b3cbe40f EA |
29 | ** STRIPQUOTES -- Strip quotes & quote bits from a string. |
30 | ** | |
31 | ** Runs through a string and strips off unquoted quote | |
32 | ** characters and quote bits. This is done in place. | |
33 | ** | |
34 | ** Parameters: | |
35 | ** s -- the string to strip. | |
cdb17311 EA |
36 | ** qf -- if set, remove actual `` " '' characters |
37 | ** as well as the quote bits. | |
b3cbe40f EA |
38 | ** |
39 | ** Returns: | |
40 | ** none. | |
41 | ** | |
42 | ** Side Effects: | |
43 | ** none. | |
44 | ** | |
b3cbe40f EA |
45 | ** Called By: |
46 | ** deliver | |
b3cbe40f EA |
47 | */ |
48 | ||
cdb17311 | 49 | stripquotes(s, qf) |
b3cbe40f | 50 | char *s; |
cdb17311 | 51 | bool qf; |
b3cbe40f EA |
52 | { |
53 | register char *p; | |
54 | register char *q; | |
55 | register char c; | |
56 | ||
cdb17311 EA |
57 | if (s == NULL) |
58 | return; | |
59 | ||
b3cbe40f EA |
60 | for (p = q = s; (c = *p++) != '\0'; ) |
61 | { | |
cdb17311 | 62 | if (c != '"' || !qf) |
b3cbe40f EA |
63 | *q++ = c & 0177; |
64 | } | |
65 | *q = '\0'; | |
66 | } | |
67 | \f/* | |
1744384a EA |
68 | ** QSTRLEN -- give me the string length assuming 0200 bits add a char |
69 | ** | |
70 | ** Parameters: | |
71 | ** s -- the string to measure. | |
72 | ** | |
73 | ** Reurns: | |
74 | ** The length of s, including space for backslash escapes. | |
75 | ** | |
76 | ** Side Effects: | |
77 | ** none. | |
78 | */ | |
79 | ||
80 | qstrlen(s) | |
81 | register char *s; | |
82 | { | |
83 | register int l = 0; | |
84 | register char c; | |
85 | ||
86 | while ((c = *s++) != '\0') | |
87 | { | |
88 | if (bitset(0200, c)) | |
89 | l++; | |
90 | l++; | |
91 | } | |
92 | return (l); | |
93 | } | |
94 | \f/* | |
1a12c7d6 EA |
95 | ** CAPITALIZE -- return a copy of a string, properly capitalized. |
96 | ** | |
97 | ** Parameters: | |
98 | ** s -- the string to capitalize. | |
99 | ** | |
100 | ** Returns: | |
101 | ** a pointer to a properly capitalized string. | |
102 | ** | |
103 | ** Side Effects: | |
104 | ** none. | |
105 | */ | |
106 | ||
107 | char * | |
108 | capitalize(s) | |
109 | register char *s; | |
110 | { | |
111 | static char buf[50]; | |
112 | register char *p; | |
113 | ||
114 | p = buf; | |
115 | ||
116 | for (;;) | |
117 | { | |
118 | while (!isalpha(*s) && *s != '\0') | |
119 | *p++ = *s++; | |
120 | if (*s == '\0') | |
121 | break; | |
122 | *p++ = toupper(*s++); | |
123 | while (isalpha(*s)) | |
124 | *p++ = *s++; | |
125 | } | |
126 | ||
127 | *p = '\0'; | |
128 | return (buf); | |
129 | } | |
130 | \f/* | |
b3cbe40f EA |
131 | ** XALLOC -- Allocate memory and bitch wildly on failure. |
132 | ** | |
133 | ** THIS IS A CLUDGE. This should be made to give a proper | |
134 | ** error -- but after all, what can we do? | |
135 | ** | |
136 | ** Parameters: | |
137 | ** sz -- size of area to allocate. | |
138 | ** | |
139 | ** Returns: | |
140 | ** pointer to data region. | |
141 | ** | |
142 | ** Side Effects: | |
143 | ** Memory is allocated. | |
b3cbe40f EA |
144 | */ |
145 | ||
146 | char * | |
147 | xalloc(sz) | |
f9566d23 | 148 | register int sz; |
b3cbe40f EA |
149 | { |
150 | register char *p; | |
17a67c62 | 151 | extern char *malloc(); |
b3cbe40f | 152 | |
17a67c62 | 153 | p = malloc((unsigned) sz); |
b3cbe40f EA |
154 | if (p == NULL) |
155 | { | |
156 | syserr("Out of memory!!"); | |
1dbda134 EA |
157 | abort(); |
158 | /* exit(EX_UNAVAILABLE); */ | |
b3cbe40f EA |
159 | } |
160 | return (p); | |
161 | } | |
162 | \f/* | |
d6a28dd8 EA |
163 | ** COPYPLIST -- copy list of pointers. |
164 | ** | |
165 | ** This routine is the equivalent of newstr for lists of | |
166 | ** pointers. | |
167 | ** | |
168 | ** Parameters: | |
169 | ** list -- list of pointers to copy. | |
170 | ** Must be NULL terminated. | |
171 | ** copycont -- if TRUE, copy the contents of the vector | |
172 | ** (which must be a string) also. | |
173 | ** | |
174 | ** Returns: | |
175 | ** a copy of 'list'. | |
176 | ** | |
177 | ** Side Effects: | |
178 | ** none. | |
179 | */ | |
180 | ||
181 | char ** | |
182 | copyplist(list, copycont) | |
183 | char **list; | |
184 | bool copycont; | |
185 | { | |
186 | register char **vp; | |
187 | register char **newvp; | |
d6a28dd8 EA |
188 | |
189 | for (vp = list; *vp != NULL; vp++) | |
190 | continue; | |
191 | ||
192 | vp++; | |
193 | ||
34fe0a9b EA |
194 | newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); |
195 | bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); | |
d6a28dd8 EA |
196 | |
197 | if (copycont) | |
198 | { | |
199 | for (vp = newvp; *vp != NULL; vp++) | |
200 | *vp = newstr(*vp); | |
201 | } | |
202 | ||
203 | return (newvp); | |
204 | } | |
205 | \f/* | |
206 | ** PRINTAV -- print argument vector. | |
207 | ** | |
208 | ** Parameters: | |
209 | ** av -- argument vector. | |
210 | ** | |
211 | ** Returns: | |
212 | ** none. | |
213 | ** | |
214 | ** Side Effects: | |
215 | ** prints av. | |
216 | */ | |
217 | ||
d6a28dd8 EA |
218 | printav(av) |
219 | register char **av; | |
220 | { | |
221 | while (*av != NULL) | |
222 | { | |
aa4ef64d EA |
223 | if (tTd(0, 44)) |
224 | printf("\n\t%08x=", *av); | |
225 | else | |
03388044 | 226 | (void) putchar(' '); |
d6a28dd8 | 227 | xputs(*av++); |
d6a28dd8 | 228 | } |
03388044 | 229 | (void) putchar('\n'); |
d6a28dd8 | 230 | } |
d6a28dd8 EA |
231 | \f/* |
232 | ** LOWER -- turn letter into lower case. | |
233 | ** | |
234 | ** Parameters: | |
235 | ** c -- character to turn into lower case. | |
236 | ** | |
237 | ** Returns: | |
238 | ** c, in lower case. | |
239 | ** | |
240 | ** Side Effects: | |
241 | ** none. | |
242 | */ | |
243 | ||
244 | char | |
245 | lower(c) | |
246 | register char c; | |
247 | { | |
0c5ea243 | 248 | return(isascii(c) && isupper(c) ? tolower(c) : c); |
d6a28dd8 EA |
249 | } |
250 | \f/* | |
251 | ** XPUTS -- put string doing control escapes. | |
252 | ** | |
253 | ** Parameters: | |
254 | ** s -- string to put. | |
255 | ** | |
256 | ** Returns: | |
257 | ** none. | |
258 | ** | |
259 | ** Side Effects: | |
260 | ** output to stdout | |
261 | */ | |
262 | ||
d6a28dd8 EA |
263 | xputs(s) |
264 | register char *s; | |
265 | { | |
266 | register char c; | |
267 | ||
04d7cb3d EA |
268 | if (s == NULL) |
269 | { | |
270 | printf("<null>"); | |
271 | return; | |
272 | } | |
03388044 | 273 | (void) putchar('"'); |
d6a28dd8 EA |
274 | while ((c = *s++) != '\0') |
275 | { | |
276 | if (!isascii(c)) | |
277 | { | |
03388044 | 278 | (void) putchar('\\'); |
d6a28dd8 EA |
279 | c &= 0177; |
280 | } | |
e9b10d8d | 281 | if (c < 040 || c >= 0177) |
d6a28dd8 | 282 | { |
03388044 | 283 | (void) putchar('^'); |
e9b10d8d | 284 | c ^= 0100; |
d6a28dd8 | 285 | } |
03388044 | 286 | (void) putchar(c); |
d6a28dd8 | 287 | } |
03388044 | 288 | (void) putchar('"'); |
29871fef | 289 | (void) fflush(stdout); |
d6a28dd8 | 290 | } |
d6a28dd8 EA |
291 | \f/* |
292 | ** MAKELOWER -- Translate a line into lower case | |
293 | ** | |
294 | ** Parameters: | |
295 | ** p -- the string to translate. If NULL, return is | |
296 | ** immediate. | |
297 | ** | |
298 | ** Returns: | |
299 | ** none. | |
300 | ** | |
301 | ** Side Effects: | |
302 | ** String pointed to by p is translated to lower case. | |
303 | ** | |
304 | ** Called By: | |
305 | ** parse | |
306 | */ | |
307 | ||
308 | makelower(p) | |
309 | register char *p; | |
310 | { | |
311 | register char c; | |
312 | ||
313 | if (p == NULL) | |
314 | return; | |
315 | for (; (c = *p) != '\0'; p++) | |
316 | if (isascii(c) && isupper(c)) | |
0c5ea243 | 317 | *p = tolower(c); |
15fc0ec5 | 318 | } |
29871fef | 319 | \f/* |
e804469b C |
320 | ** BUILDFNAME -- build full name from gecos style entry. |
321 | ** | |
322 | ** This routine interprets the strange entry that would appear | |
323 | ** in the GECOS field of the password file. | |
2b5e3c25 EA |
324 | ** |
325 | ** Parameters: | |
e804469b C |
326 | ** p -- name to build. |
327 | ** login -- the login name of this user (for &). | |
328 | ** buf -- place to put the result. | |
2b5e3c25 EA |
329 | ** |
330 | ** Returns: | |
331 | ** none. | |
332 | ** | |
333 | ** Side Effects: | |
334 | ** none. | |
335 | */ | |
336 | ||
e804469b C |
337 | buildfname(p, login, buf) |
338 | register char *p; | |
339 | char *login; | |
2b5e3c25 EA |
340 | char *buf; |
341 | { | |
342 | register char *bp = buf; | |
343 | ||
b14547d5 EA |
344 | if (*p == '*') |
345 | p++; | |
48ae2358 | 346 | while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') |
2b5e3c25 EA |
347 | { |
348 | if (*p == '&') | |
349 | { | |
e804469b | 350 | (void) strcpy(bp, login); |
2b5e3c25 EA |
351 | *bp = toupper(*bp); |
352 | while (*bp != '\0') | |
353 | bp++; | |
354 | p++; | |
355 | } | |
356 | else | |
357 | *bp++ = *p++; | |
358 | } | |
359 | *bp = '\0'; | |
360 | } | |
361 | \f/* | |
f6a0cc15 EA |
362 | ** SAFEFILE -- return true if a file exists and is safe for a user. |
363 | ** | |
364 | ** Parameters: | |
365 | ** fn -- filename to check. | |
366 | ** uid -- uid to compare against. | |
367 | ** mode -- mode bits that must match. | |
368 | ** | |
369 | ** Returns: | |
370 | ** TRUE if fn exists, is owned by uid, and matches mode. | |
371 | ** FALSE otherwise. | |
372 | ** | |
373 | ** Side Effects: | |
374 | ** none. | |
375 | */ | |
376 | ||
377 | bool | |
378 | safefile(fn, uid, mode) | |
379 | char *fn; | |
380 | int uid; | |
381 | int mode; | |
382 | { | |
383 | struct stat stbuf; | |
384 | ||
385 | if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && | |
386 | (stbuf.st_mode & mode) == mode) | |
387 | return (TRUE); | |
70faa7c8 | 388 | errno = 0; |
f6a0cc15 EA |
389 | return (FALSE); |
390 | } | |
391 | \f/* | |
2768afe3 EA |
392 | ** FIXCRLF -- fix <CR><LF> in line. |
393 | ** | |
394 | ** Looks for the <CR><LF> combination and turns it into the | |
395 | ** UNIX canonical <NL> character. It only takes one line, | |
396 | ** i.e., it is assumed that the first <NL> found is the end | |
397 | ** of the line. | |
398 | ** | |
399 | ** Parameters: | |
400 | ** line -- the line to fix. | |
401 | ** stripnl -- if true, strip the newline also. | |
402 | ** | |
403 | ** Returns: | |
404 | ** none. | |
405 | ** | |
406 | ** Side Effects: | |
407 | ** line is changed in place. | |
408 | */ | |
409 | ||
410 | fixcrlf(line, stripnl) | |
411 | char *line; | |
412 | bool stripnl; | |
413 | { | |
414 | register char *p; | |
415 | ||
416 | p = index(line, '\n'); | |
417 | if (p == NULL) | |
418 | return; | |
f90b4150 | 419 | if (p > line && p[-1] == '\r') |
2768afe3 EA |
420 | p--; |
421 | if (!stripnl) | |
422 | *p++ = '\n'; | |
423 | *p = '\0'; | |
424 | } | |
425 | \f/* | |
5c373723 EA |
426 | ** DFOPEN -- determined file open |
427 | ** | |
428 | ** This routine has the semantics of fopen, except that it will | |
429 | ** keep trying a few times to make this happen. The idea is that | |
430 | ** on very loaded systems, we may run out of resources (inodes, | |
431 | ** whatever), so this tries to get around it. | |
432 | */ | |
433 | ||
434 | FILE * | |
435 | dfopen(filename, mode) | |
436 | char *filename; | |
437 | char *mode; | |
438 | { | |
439 | register int tries; | |
440 | register FILE *fp; | |
5c373723 EA |
441 | |
442 | for (tries = 0; tries < 10; tries++) | |
443 | { | |
901911f8 | 444 | sleep((unsigned) (10 * tries)); |
5c373723 EA |
445 | errno = 0; |
446 | fp = fopen(filename, mode); | |
7338e3d4 EA |
447 | if (fp != NULL) |
448 | break; | |
449 | if (errno != ENFILE && errno != EINTR) | |
5c373723 EA |
450 | break; |
451 | } | |
70faa7c8 | 452 | errno = 0; |
5c373723 EA |
453 | return (fp); |
454 | } | |
b85ad418 EA |
455 | \f/* |
456 | ** PUTLINE -- put a line like fputs obeying SMTP conventions | |
457 | ** | |
d08bed81 EA |
458 | ** This routine always guarantees outputing a newline (or CRLF, |
459 | ** as appropriate) at the end of the string. | |
460 | ** | |
b85ad418 EA |
461 | ** Parameters: |
462 | ** l -- line to put. | |
463 | ** fp -- file to put it onto. | |
4db45bf1 | 464 | ** m -- the mailer used to control output. |
b85ad418 EA |
465 | ** |
466 | ** Returns: | |
467 | ** none | |
468 | ** | |
469 | ** Side Effects: | |
470 | ** output of l to fp. | |
471 | */ | |
472 | ||
d08bed81 | 473 | # define SMTPLINELIM 990 /* maximum line length */ |
b85ad418 | 474 | |
4db45bf1 | 475 | putline(l, fp, m) |
d08bed81 | 476 | register char *l; |
b85ad418 | 477 | FILE *fp; |
4db45bf1 | 478 | MAILER *m; |
b85ad418 EA |
479 | { |
480 | register char *p; | |
d08bed81 | 481 | char svchar; |
b85ad418 | 482 | |
f3e66638 EA |
483 | /* strip out 0200 bits -- these can look like TELNET protocol */ |
484 | if (bitnset(M_LIMITS, m->m_flags)) | |
485 | { | |
486 | p = l; | |
487 | while ((*p++ &= ~0200) != 0) | |
488 | continue; | |
489 | } | |
490 | ||
d08bed81 | 491 | do |
b85ad418 | 492 | { |
d08bed81 EA |
493 | /* find the end of the line */ |
494 | p = index(l, '\n'); | |
495 | if (p == NULL) | |
496 | p = &l[strlen(l)]; | |
b85ad418 | 497 | |
d08bed81 | 498 | /* check for line overflow */ |
f3e66638 | 499 | while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags)) |
d08bed81 EA |
500 | { |
501 | register char *q = &l[SMTPLINELIM - 1]; | |
502 | ||
503 | svchar = *q; | |
504 | *q = '\0'; | |
1dbda134 | 505 | if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) |
03388044 | 506 | (void) putc('.', fp); |
d08bed81 | 507 | fputs(l, fp); |
03388044 | 508 | (void) putc('!', fp); |
e9b10d8d | 509 | fputs(m->m_eol, fp); |
d08bed81 EA |
510 | *q = svchar; |
511 | l = q; | |
512 | } | |
b85ad418 | 513 | |
d08bed81 EA |
514 | /* output last part */ |
515 | svchar = *p; | |
516 | *p = '\0'; | |
1dbda134 | 517 | if (l[0] == '.' && bitnset(M_XDOT, m->m_flags)) |
03388044 | 518 | (void) putc('.', fp); |
b85ad418 | 519 | fputs(l, fp); |
e9b10d8d | 520 | fputs(m->m_eol, fp); |
d08bed81 EA |
521 | *p = svchar; |
522 | l = p; | |
523 | if (*l == '\n') | |
524 | l++; | |
525 | } while (l[0] != '\0'); | |
b85ad418 | 526 | } |
9678c96d EA |
527 | \f/* |
528 | ** XUNLINK -- unlink a file, doing logging as appropriate. | |
529 | ** | |
530 | ** Parameters: | |
531 | ** f -- name of file to unlink. | |
532 | ** | |
533 | ** Returns: | |
534 | ** none. | |
535 | ** | |
536 | ** Side Effects: | |
537 | ** f is unlinked. | |
538 | */ | |
539 | ||
540 | xunlink(f) | |
541 | char *f; | |
542 | { | |
543 | register int i; | |
544 | ||
545 | # ifdef LOG | |
546 | if (LogLevel > 20) | |
2cce0c26 | 547 | syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); |
9678c96d EA |
548 | # endif LOG |
549 | ||
550 | i = unlink(f); | |
551 | # ifdef LOG | |
552 | if (i < 0 && LogLevel > 21) | |
6d06102a | 553 | syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); |
9678c96d EA |
554 | # endif LOG |
555 | } | |
2439b900 | 556 | \f/* |
e4581b86 | 557 | ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. |
2439b900 EA |
558 | ** |
559 | ** Parameters: | |
560 | ** buf -- place to put the input line. | |
561 | ** siz -- size of buf. | |
562 | ** fp -- file to read from. | |
563 | ** | |
564 | ** Returns: | |
e009f4f4 EA |
565 | ** NULL on error (including timeout). This will also leave |
566 | ** buf containing a null string. | |
2439b900 EA |
567 | ** buf otherwise. |
568 | ** | |
569 | ** Side Effects: | |
570 | ** none. | |
571 | */ | |
572 | ||
e4581b86 | 573 | static jmp_buf CtxReadTimeout; |
2439b900 EA |
574 | |
575 | char * | |
576 | sfgets(buf, siz, fp) | |
577 | char *buf; | |
578 | int siz; | |
579 | FILE *fp; | |
580 | { | |
6d06102a | 581 | register EVENT *ev = NULL; |
2439b900 EA |
582 | register char *p; |
583 | extern readtimeout(); | |
584 | ||
e4581b86 | 585 | /* set the timeout */ |
6d06102a | 586 | if (ReadTimeout != 0) |
e4581b86 EA |
587 | { |
588 | if (setjmp(CtxReadTimeout) != 0) | |
589 | { | |
2e15a2d8 | 590 | # ifdef LOG |
ab4889ea MK |
591 | syslog(LOG_NOTICE, |
592 | "timeout waiting for input from %s\n", | |
593 | RealHostName); | |
2e15a2d8 | 594 | # endif |
ab4889ea MK |
595 | errno = 0; |
596 | usrerr("timeout waiting for input"); | |
77872b93 | 597 | buf[0] = '\0'; |
e4581b86 EA |
598 | return (NULL); |
599 | } | |
ce7cfd4c | 600 | ev = setevent((time_t) ReadTimeout, readtimeout, 0); |
e4581b86 EA |
601 | } |
602 | ||
603 | /* try to read */ | |
e009f4f4 EA |
604 | p = NULL; |
605 | while (p == NULL && !feof(fp) && !ferror(fp)) | |
6d06102a EA |
606 | { |
607 | errno = 0; | |
608 | p = fgets(buf, siz, fp); | |
e009f4f4 EA |
609 | if (errno == EINTR) |
610 | clearerr(fp); | |
611 | } | |
e4581b86 EA |
612 | |
613 | /* clear the event if it has not sprung */ | |
2439b900 | 614 | clrevent(ev); |
e4581b86 EA |
615 | |
616 | /* clean up the books and exit */ | |
04d7cb3d | 617 | LineNumber++; |
e009f4f4 | 618 | if (p == NULL) |
4ed73359 | 619 | { |
e009f4f4 | 620 | buf[0] = '\0'; |
4ed73359 EA |
621 | return (NULL); |
622 | } | |
623 | for (p = buf; *p != '\0'; p++) | |
624 | *p &= ~0200; | |
625 | return (buf); | |
2439b900 EA |
626 | } |
627 | ||
628 | static | |
629 | readtimeout() | |
630 | { | |
e4581b86 | 631 | longjmp(CtxReadTimeout, 1); |
2439b900 | 632 | } |
6a86d693 EA |
633 | \f/* |
634 | ** FGETFOLDED -- like fgets, but know about folded lines. | |
635 | ** | |
636 | ** Parameters: | |
637 | ** buf -- place to put result. | |
638 | ** n -- bytes available. | |
639 | ** f -- file to read from. | |
640 | ** | |
641 | ** Returns: | |
642 | ** buf on success, NULL on error or EOF. | |
643 | ** | |
644 | ** Side Effects: | |
645 | ** buf gets lines from f, with continuation lines (lines | |
646 | ** with leading white space) appended. CRLF's are mapped | |
647 | ** into single newlines. Any trailing NL is stripped. | |
648 | */ | |
649 | ||
650 | char * | |
651 | fgetfolded(buf, n, f) | |
652 | char *buf; | |
653 | register int n; | |
654 | FILE *f; | |
655 | { | |
656 | register char *p = buf; | |
657 | register int i; | |
658 | ||
659 | n--; | |
2975cf68 | 660 | while ((i = getc(f)) != EOF) |
6a86d693 | 661 | { |
2975cf68 EA |
662 | if (i == '\r') |
663 | { | |
664 | i = getc(f); | |
665 | if (i != '\n') | |
666 | { | |
667 | if (i != EOF) | |
03388044 | 668 | (void) ungetc(i, f); |
2975cf68 EA |
669 | i = '\r'; |
670 | } | |
671 | } | |
672 | if (--n > 0) | |
673 | *p++ = i; | |
674 | if (i == '\n') | |
675 | { | |
676 | LineNumber++; | |
677 | i = getc(f); | |
678 | if (i != EOF) | |
03388044 | 679 | (void) ungetc(i, f); |
2975cf68 EA |
680 | if (i != ' ' && i != '\t') |
681 | { | |
682 | *--p = '\0'; | |
683 | return (buf); | |
684 | } | |
685 | } | |
6a86d693 EA |
686 | } |
687 | return (NULL); | |
688 | } | |
96476cab | 689 | \f/* |
88039044 EA |
690 | ** CURTIME -- return current time. |
691 | ** | |
692 | ** Parameters: | |
693 | ** none. | |
694 | ** | |
695 | ** Returns: | |
696 | ** the current time. | |
697 | ** | |
698 | ** Side Effects: | |
699 | ** none. | |
700 | */ | |
701 | ||
702 | time_t | |
703 | curtime() | |
704 | { | |
705 | auto time_t t; | |
706 | ||
707 | (void) time(&t); | |
708 | return (t); | |
709 | } | |
fbd53483 EA |
710 | \f/* |
711 | ** ATOBOOL -- convert a string representation to boolean. | |
712 | ** | |
713 | ** Defaults to "TRUE" | |
714 | ** | |
715 | ** Parameters: | |
716 | ** s -- string to convert. Takes "tTyY" as true, | |
717 | ** others as false. | |
718 | ** | |
719 | ** Returns: | |
720 | ** A boolean representation of the string. | |
721 | ** | |
722 | ** Side Effects: | |
723 | ** none. | |
724 | */ | |
725 | ||
726 | bool | |
727 | atobool(s) | |
728 | register char *s; | |
729 | { | |
730 | if (*s == '\0' || index("tTyY", *s) != NULL) | |
731 | return (TRUE); | |
732 | return (FALSE); | |
733 | } | |
6db97a2f EA |
734 | \f/* |
735 | ** ATOOCT -- convert a string representation to octal. | |
736 | ** | |
737 | ** Parameters: | |
738 | ** s -- string to convert. | |
739 | ** | |
740 | ** Returns: | |
741 | ** An integer representing the string interpreted as an | |
742 | ** octal number. | |
743 | ** | |
744 | ** Side Effects: | |
745 | ** none. | |
746 | */ | |
747 | ||
748 | atooct(s) | |
749 | register char *s; | |
750 | { | |
751 | register int i = 0; | |
752 | ||
753 | while (*s >= '0' && *s <= '7') | |
754 | i = (i << 3) | (*s++ - '0'); | |
755 | return (i); | |
756 | } | |
7338e3d4 EA |
757 | \f/* |
758 | ** WAITFOR -- wait for a particular process id. | |
759 | ** | |
760 | ** Parameters: | |
761 | ** pid -- process id to wait for. | |
762 | ** | |
763 | ** Returns: | |
764 | ** status of pid. | |
765 | ** -1 if pid never shows up. | |
766 | ** | |
767 | ** Side Effects: | |
768 | ** none. | |
769 | */ | |
770 | ||
771 | waitfor(pid) | |
772 | int pid; | |
773 | { | |
774 | auto int st; | |
775 | int i; | |
776 | ||
777 | do | |
778 | { | |
779 | errno = 0; | |
780 | i = wait(&st); | |
781 | } while ((i >= 0 || errno == EINTR) && i != pid); | |
782 | if (i < 0) | |
783 | st = -1; | |
784 | return (st); | |
785 | } | |
786 | \f/* | |
1dbda134 EA |
787 | ** BITINTERSECT -- tell if two bitmaps intersect |
788 | ** | |
789 | ** Parameters: | |
790 | ** a, b -- the bitmaps in question | |
791 | ** | |
792 | ** Returns: | |
793 | ** TRUE if they have a non-null intersection | |
794 | ** FALSE otherwise | |
795 | ** | |
796 | ** Side Effects: | |
797 | ** none. | |
798 | */ | |
799 | ||
800 | bool | |
801 | bitintersect(a, b) | |
802 | BITMAP a; | |
803 | BITMAP b; | |
804 | { | |
805 | int i; | |
806 | ||
807 | for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) | |
808 | if ((a[i] & b[i]) != 0) | |
809 | return (TRUE); | |
810 | return (FALSE); | |
811 | } | |
812 | \f/* | |
813 | ** BITZEROP -- tell if a bitmap is all zero | |
814 | ** | |
815 | ** Parameters: | |
816 | ** map -- the bit map to check | |
817 | ** | |
818 | ** Returns: | |
819 | ** TRUE if map is all zero. | |
820 | ** FALSE if there are any bits set in map. | |
821 | ** | |
822 | ** Side Effects: | |
823 | ** none. | |
824 | */ | |
825 | ||
826 | bool | |
827 | bitzerop(map) | |
828 | BITMAP map; | |
829 | { | |
830 | int i; | |
831 | ||
832 | for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) | |
833 | if (map[i] != 0) | |
834 | return (FALSE); | |
835 | return (TRUE); | |
836 | } |