xref: /illumos-gate/usr/src/lib/libc/port/stdio/getline.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include "lint.h"
27 #include "file64.h"
28 #include "mtlib.h"
29 #include <stdio.h>
30 #include <errno.h>
31 #include <thread.h>
32 #include <synch.h>
33 #include <unistd.h>
34 #include <limits.h>
35 #include <malloc.h>
36 #include <sys/types.h>
37 #include "stdiom.h"
38 
39 #define	LINESZ	128	/* initial guess for a NULL *lineptr */
40 
41 ssize_t
42 getdelim(char **_RESTRICT_KYWD lineptr, size_t *_RESTRICT_KYWD n,
43     int delimiter, FILE *_RESTRICT_KYWD iop)
44 {
45 	rmutex_t *lk;
46 	char *ptr;
47 	size_t size;
48 	int c;
49 	size_t cnt;
50 
51 	if (lineptr == NULL || n == NULL ||
52 	    delimiter < 0 || delimiter > UCHAR_MAX) {
53 		errno = EINVAL;
54 		return (-1);
55 	}
56 
57 	if (*lineptr == NULL || *n < LINESZ) {	/* initial allocation */
58 		if ((*lineptr = realloc(*lineptr, LINESZ)) == NULL) {
59 			errno = ENOMEM;
60 			return (-1);
61 		}
62 		*n = LINESZ;
63 	}
64 	ptr = *lineptr;
65 	size = *n;
66 	cnt = 0;
67 
68 	FLOCKFILE(lk, iop);
69 
70 	_SET_ORIENTATION_BYTE(iop);
71 
72 	do {
73 		c = (--iop->_cnt < 0) ? __filbuf(iop) : *iop->_ptr++;
74 		if (c == EOF)
75 			break;
76 		*ptr++ = c;
77 		if (++cnt == size) {	/* must reallocate */
78 			if ((ptr = realloc(*lineptr, 2 * size)) == NULL) {
79 				FUNLOCKFILE(lk);
80 				ptr = *lineptr + size - 1;
81 				*ptr = '\0';
82 				errno = ENOMEM;
83 				return (-1);
84 			}
85 			*lineptr = ptr;
86 			ptr += size;
87 			*n = size = 2 * size;
88 		}
89 	} while (c != delimiter);
90 
91 	*ptr = '\0';
92 
93 	FUNLOCKFILE(lk);
94 	if (cnt > SSIZE_MAX) {
95 		errno = EOVERFLOW;
96 		return (-1);
97 	}
98 	return (cnt ? cnt : -1);
99 }
100 
101 ssize_t
102 getline(char **_RESTRICT_KYWD lineptr, size_t *_RESTRICT_KYWD n,
103     FILE *_RESTRICT_KYWD iop)
104 {
105 	return (getdelim(lineptr, n, '\n', iop));
106 }
107