1 /* 2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Chris Torek. 9 * 10 * By using this file, you agree to the terms and conditions set 11 * forth in the LICENSE file which can be found at the top level of 12 * the sendmail distribution. 13 */ 14 15 #include <sm/gen.h> 16 SM_RCSID("@(#)$Id: fget.c,v 1.24 2001/09/11 04:04:48 gshapiro Exp $") 17 #include <stdlib.h> 18 #include <string.h> 19 #include <sm/io.h> 20 #include <sm/assert.h> 21 #include "local.h" 22 23 /* 24 ** SM_IO_FGETS -- get a string from a file 25 ** 26 ** Read at most n-1 characters from the given file. 27 ** Stop when a newline has been read, or the count ('n') runs out. 28 ** 29 ** Parameters: 30 ** fp -- the file to read from 31 ** timeout -- time to complete reading the string in milliseconds 32 ** buf -- buffer to place read string in 33 ** n -- size of 'buf' 34 ** 35 ** Returns: 36 ** success: returns value of 'buf' 37 ** failure: NULL (no characters were read) 38 ** timeout: NULL and errno set to EAGAIN 39 ** 40 ** Side Effects: 41 ** may move the file pointer 42 */ 43 44 char * 45 sm_io_fgets(fp, timeout, buf, n) 46 register SM_FILE_T *fp; 47 int timeout; 48 char *buf; 49 register int n; 50 { 51 register int len; 52 register char *s; 53 register unsigned char *p, *t; 54 55 SM_REQUIRE_ISA(fp, SmFileMagic); 56 if (n <= 0) /* sanity check */ 57 return NULL; 58 59 s = buf; 60 n--; /* leave space for NUL */ 61 while (n > 0) 62 { 63 /* If the buffer is empty, refill it. */ 64 if ((len = fp->f_r) <= 0) 65 { 66 67 /* 68 ** Timeout is only passed if we can't get the data 69 ** from the buffer (which is counted as immediately). 70 */ 71 72 if (sm_refill(fp, timeout) != 0) 73 { 74 /* EOF/error: stop with partial or no line */ 75 if (s == buf) 76 return NULL; 77 break; 78 } 79 len = fp->f_r; 80 } 81 p = fp->f_p; 82 83 /* 84 ** Scan through at most n bytes of the current buffer, 85 ** looking for '\n'. If found, copy up to and including 86 ** newline, and stop. Otherwise, copy entire chunk 87 ** and loop. 88 */ 89 90 if (len > n) 91 len = n; 92 t = (unsigned char *) memchr((void *) p, '\n', len); 93 if (t != NULL) 94 { 95 len = ++t - p; 96 fp->f_r -= len; 97 fp->f_p = t; 98 (void) memcpy((void *) s, (void *) p, len); 99 s[len] = 0; 100 return buf; 101 } 102 fp->f_r -= len; 103 fp->f_p += len; 104 (void) memcpy((void *) s, (void *) p, len); 105 s += len; 106 n -= len; 107 } 108 *s = 0; 109 return buf; 110 } 111