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