PostgreSQL Source Code
git master
pg_get_line.c
Go to the documentation of this file.
1
/*-------------------------------------------------------------------------
2
*
3
* pg_get_line.c
4
* fgets() with an expansible result buffer
5
*
6
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
8
*
9
*
10
* IDENTIFICATION
11
* src/common/pg_get_line.c
12
*
13
*-------------------------------------------------------------------------
14
*/
15
#ifndef FRONTEND
16
#include "
postgres.h
"
17
#else
18
#include "
postgres_fe.h
"
19
#endif
20
21
#include <setjmp.h>
22
23
#include "
common/string.h
"
24
#include "
lib/stringinfo.h
"
25
26
27
/*
28
* pg_get_line()
29
*
30
* This is meant to be equivalent to fgets(), except that instead of
31
* reading into a caller-supplied, fixed-size buffer, it reads into
32
* a palloc'd (in frontend, really malloc'd) string, which is resized
33
* as needed to handle indefinitely long input lines. The caller is
34
* responsible for pfree'ing the result string when appropriate.
35
*
36
* As with fgets(), returns NULL if there is a read error or if no
37
* characters are available before EOF. The caller can distinguish
38
* these cases by checking ferror(stream).
39
*
40
* Since this is meant to be equivalent to fgets(), the trailing newline
41
* (if any) is not stripped. Callers may wish to apply pg_strip_crlf().
42
*
43
* Note that while I/O errors are reflected back to the caller to be
44
* dealt with, an OOM condition for the palloc'd buffer will not be;
45
* there'll be an ereport(ERROR) or exit(1) inside stringinfo.c.
46
*
47
* Also note that the palloc'd buffer is usually a lot longer than
48
* strictly necessary, so it may be inadvisable to use this function
49
* to collect lots of long-lived data. A less memory-hungry option
50
* is to use pg_get_line_buf() or pg_get_line_append() in a loop,
51
* then pstrdup() each line.
52
*
53
* prompt_ctx can optionally be provided to allow this function to be
54
* canceled via an existing SIGINT signal handler that will longjmp to the
55
* specified place only when *(prompt_ctx->enabled) is true. If canceled,
56
* this function returns NULL, and prompt_ctx->canceled is set to true.
57
*/
58
char
*
59
pg_get_line
(FILE *stream,
PromptInterruptContext
*prompt_ctx)
60
{
61
StringInfoData
buf
;
62
63
initStringInfo
(&
buf
);
64
65
if
(!
pg_get_line_append
(stream, &
buf
, prompt_ctx))
66
{
67
/* ensure that free() doesn't mess up errno */
68
int
save_errno = errno;
69
70
pfree
(
buf
.data);
71
errno = save_errno;
72
return
NULL;
73
}
74
75
return
buf
.data;
76
}
77
78
/*
79
* pg_get_line_buf()
80
*
81
* This has similar behavior to pg_get_line(), and thence to fgets(),
82
* except that the collected data is returned in a caller-supplied
83
* StringInfo buffer. This is a convenient API for code that just
84
* wants to read and process one line at a time, without any artificial
85
* limit on line length.
86
*
87
* Returns true if a line was successfully collected (including the
88
* case of a non-newline-terminated line at EOF). Returns false if
89
* there was an I/O error or no data was available before EOF.
90
* (Check ferror(stream) to distinguish these cases.)
91
*
92
* In the false-result case, buf is reset to empty.
93
*/
94
bool
95
pg_get_line_buf
(FILE *stream,
StringInfo
buf
)
96
{
97
/* We just need to drop any data from the previous call */
98
resetStringInfo
(
buf
);
99
return
pg_get_line_append
(stream,
buf
, NULL);
100
}
101
102
/*
103
* pg_get_line_append()
104
*
105
* This has similar behavior to pg_get_line(), and thence to fgets(),
106
* except that the collected data is appended to whatever is in *buf.
107
* This is useful in preference to pg_get_line_buf() if the caller wants
108
* to merge some lines together, e.g. to implement backslash continuation.
109
*
110
* Returns true if a line was successfully collected (including the
111
* case of a non-newline-terminated line at EOF). Returns false if
112
* there was an I/O error or no data was available before EOF.
113
* (Check ferror(stream) to distinguish these cases.)
114
*
115
* In the false-result case, the contents of *buf are logically unmodified,
116
* though it's possible that the buffer has been resized.
117
*
118
* prompt_ctx can optionally be provided to allow this function to be
119
* canceled via an existing SIGINT signal handler that will longjmp to the
120
* specified place only when *(prompt_ctx->enabled) is true. If canceled,
121
* this function returns false, and prompt_ctx->canceled is set to true.
122
*/
123
bool
124
pg_get_line_append
(FILE *stream,
StringInfo
buf
,
125
PromptInterruptContext
*prompt_ctx)
126
{
127
int
orig_len =
buf
->len;
128
129
if
(prompt_ctx && sigsetjmp(*((sigjmp_buf *) prompt_ctx->
jmpbuf
), 1) != 0)
130
{
131
/* Got here with longjmp */
132
prompt_ctx->
canceled
=
true
;
133
/* Discard any data we collected before detecting error */
134
buf
->len = orig_len;
135
buf
->data[orig_len] =
'\0'
;
136
return
false
;
137
}
138
139
/* Loop until newline or EOF/error */
140
for
(;;)
141
{
142
char
*
res
;
143
144
/* Enable longjmp while waiting for input */
145
if
(prompt_ctx)
146
*(prompt_ctx->
enabled
) =
true
;
147
148
/* Read some data, appending it to whatever we already have */
149
res
= fgets(
buf
->data +
buf
->len,
buf
->maxlen -
buf
->len, stream);
150
151
/* Disable longjmp again, then break if fgets failed */
152
if
(prompt_ctx)
153
*(prompt_ctx->
enabled
) =
false
;
154
155
if
(
res
== NULL)
156
break
;
157
158
/* Got data, so update buf->len */
159
buf
->len += strlen(
buf
->data +
buf
->len);
160
161
/* Done if we have collected a newline */
162
if
(
buf
->len > orig_len &&
buf
->data[
buf
->len - 1] ==
'\n'
)
163
return
true
;
164
165
/* Make some more room in the buffer, and loop to read more data */
166
enlargeStringInfo
(
buf
, 128);
167
}
168
169
/* Check for I/O errors and EOF */
170
if
(ferror(stream) ||
buf
->len == orig_len)
171
{
172
/* Discard any data we collected before detecting error */
173
buf
->len = orig_len;
174
buf
->data[orig_len] =
'\0'
;
175
return
false
;
176
}
177
178
/* No newline at EOF, but we did collect some data */
179
return
true
;
180
}
res
static void PGresult * res
Definition:
dblink.c:165
pfree
void pfree(void *pointer)
Definition:
mcxt.c:1521
pg_get_line
char * pg_get_line(FILE *stream, PromptInterruptContext *prompt_ctx)
Definition:
pg_get_line.c:59
pg_get_line_append
bool pg_get_line_append(FILE *stream, StringInfo buf, PromptInterruptContext *prompt_ctx)
Definition:
pg_get_line.c:124
pg_get_line_buf
bool pg_get_line_buf(FILE *stream, StringInfo buf)
Definition:
pg_get_line.c:95
buf
static char * buf
Definition:
pg_test_fsync.c:73
postgres.h
postgres_fe.h
string.h
resetStringInfo
void resetStringInfo(StringInfo str)
Definition:
stringinfo.c:78
enlargeStringInfo
void enlargeStringInfo(StringInfo str, int needed)
Definition:
stringinfo.c:289
initStringInfo
void initStringInfo(StringInfo str)
Definition:
stringinfo.c:59
stringinfo.h
PromptInterruptContext
Definition:
string.h:18
PromptInterruptContext::enabled
volatile sig_atomic_t * enabled
Definition:
string.h:21
PromptInterruptContext::canceled
bool canceled
Definition:
string.h:22
PromptInterruptContext::jmpbuf
void * jmpbuf
Definition:
string.h:20
StringInfoData
Definition:
stringinfo.h:47
src
common
pg_get_line.c
Generated on Sun Sep 8 2024 00:13:24 for PostgreSQL Source Code by
1.9.1