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>
16SM_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
44int
45sm_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