1 /* 2 * Copyright (c) 2000-2001, 2013 Proofpoint, 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.26 2013-11-22 20:51:42 ca 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: number of characters 37 ** failure: -1 38 ** timeout: -1 and errno set to EAGAIN 39 ** 40 ** Side Effects: 41 ** may move the file pointer 42 */ 43 44 int 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 int len, r; 52 char *s; 53 unsigned char *p, *t; 54 55 SM_REQUIRE_ISA(fp, SmFileMagic); 56 if (n <= 0) /* sanity check */ 57 return -1; 58 59 s = buf; 60 n--; /* leave space for NUL */ 61 r = 0; 62 while (n > 0) 63 { 64 /* If the buffer is empty, refill it. */ 65 if ((len = fp->f_r) <= 0) 66 { 67 68 /* 69 ** Timeout is only passed if we can't get the data 70 ** from the buffer (which is counted as immediately). 71 */ 72 73 if (sm_refill(fp, timeout) != 0) 74 { 75 /* EOF/error: stop with partial or no line */ 76 if (s == buf) 77 return -1; 78 break; 79 } 80 len = fp->f_r; 81 } 82 p = fp->f_p; 83 84 /* 85 ** Scan through at most n bytes of the current buffer, 86 ** looking for '\n'. If found, copy up to and including 87 ** newline, and stop. Otherwise, copy entire chunk 88 ** and loop. 89 */ 90 91 if (len > n) 92 len = n; 93 t = (unsigned char *) memchr((void *) p, '\n', len); 94 if (t != NULL) 95 { 96 len = ++t - p; 97 r += len; 98 fp->f_r -= len; 99 fp->f_p = t; 100 (void) memcpy((void *) s, (void *) p, len); 101 s[len] = 0; 102 return r; 103 } 104 fp->f_r -= len; 105 fp->f_p += len; 106 (void) memcpy((void *) s, (void *) p, len); 107 s += len; 108 r += len; 109 n -= len; 110 } 111 *s = 0; 112 return r; 113 } 114