/
fgetln.c
135 lines (110 loc) · 3.71 KB
/
fgetln.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* fgetline: Read one line of input and return a pointer to
that line. Necessary space is obtained from malloc.
(char *) NULL is returned on EOF.
Andy Dougherty doughera@lafcol.lafayette.edu
Dept. of Physics
Lafayette College, Easton PA 18042
Successive calls to fgetline() overwrite the original buffer.
If you want to preserve the data, you must do something like
the following (the +1's are for '\0' characters):
tmp = fgetline(fp);
ntmp = Ealloc(strlen(tmp)+1, sizeof(char));
strncpy(ntmp, tmp, strlen(tmp)+1);
A line is defined as all characters up to (and including) the next
newline character or end of file.
The string is terminated by a NULL character.
* Version 1.1 A. Dougherty 2/7/94
Don't call realloc() just to save a few bytes.
Check return value from realloc(). (NULL is allowed under POSIX,
though I've never hit it.)
* Version 1.0 A. Dougherty 2/27/91
This fgetline implementation was written by Andrew Dougherty
<doughera@lafayette.edu>. I hearby place it in the public domain.
As a courtesy, please leave my name attached to the source.
This code comes with no warranty whatsoever, and I take no
responsibility for any consequences of its use.
*/
/* Algorithm: A local static buffer "buf" is maintained. The current
length (space available) is in the static variable "avail".
Read in characters into this buffer. If need more space, call
malloc().
Aside: We have computed strlen(buf) in this function. It
seems a shame to throw it away.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#define LINELEN 128 /* A decent guess that should only rarely be
overwritten.
*/
#define OK_TO_WASTE 512 /* Don't bother trying to realloc() back to
a smaller buffer if you'd only end up
wasting OK_TO_WASTE bytes.
*/
void *Emalloc(size_t len) /* David */
{
char *p;
p=malloc(len);
if (p == NULL) {
perror("out of memory (Emalloc)");
exit(2);
}
return p;
}
void *Erealloc(char *p, size_t len) /* David */
{
p=realloc(p, len);
if (p == NULL) {
perror("out of memory (Erealloc)");
exit(2);
}
return p;
}
char *
fgetln(FILE *fp, size_t *length)
{
static char *buf = NULL;
static size_t avail = 0;
int c;
char *p; /* Temporary used for reducing length. */
int len;
if (avail == 0)
{
buf = (char *) Emalloc(LINELEN * sizeof(char));
avail = LINELEN;
}
len = 0; /* Current length */
while ((c=getc(fp)) != EOF)
{
if (len >= avail) /* Need to ask for space */
{
avail += LINELEN; /* Maybe avail *= 2 would be better */
buf = (char *) Erealloc((void *) buf, avail * sizeof(char));
}
buf[len] = c;
len++;
if (c == '\n')
break;
}
if (c == EOF && len == 0)
return (char *) NULL;
/* Add terminating '\0' character */
if (len >= avail) /* Need 1 more space */
buf = (char *) Erealloc((void *) buf, (len+1) * sizeof(char));
buf[len] = '\0';
/* Should we bother to try reclaiming memory? (Otherwise, this
function will hold onto enough memory to hold the longest
line for the entire duration of the program.)
*/
if (avail - len > OK_TO_WASTE)
{
p = (char *) Erealloc((void *) buf, (len+1) * sizeof(char));
if (p != NULL)
{
buf = p;
avail = len + 1;
}
}
*length=len-1;
return buf;
}