"Fossies" - the Fresh Open Source Software Archive 
Member "tin-2.6.2/src/read.c" (9 Dec 2022, 10778 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "read.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.6.1_vs_2.6.2.
1 /*
2 * Project : tin - a Usenet reader
3 * Module : read.c
4 * Author : Jason Faultless <jason@altarstone.com>
5 * Created : 1997-04-10
6 * Updated : 2022-09-19
7 *
8 * Copyright (c) 1997-2023 Jason Faultless <jason@altarstone.com>
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * 3. Neither the name of the copyright holder nor the names of its
23 * contributors may be used to endorse or promote products derived from
24 * this software without specific prior written permission.
25 *
26 * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39
40 #ifndef TIN_H
41 # include "tin.h"
42 #endif /* !TIN_H */
43 #ifndef TNNTP_H
44 # include "tnntp.h"
45 #endif /* !TNNTP_H */
46 #ifndef TIN_MISSING_FD_H
47 # include <missing_fd.h>
48 #endif /* TIN_MISSING_FD_H */
49
50 /*
51 * The initial and expansion sizes to use for allocating read data
52 */
53 #define INIT 512
54 #define RCHUNK 256
55
56 /*
57 * Global error flag. Set if something abnormal happens during file I/O
58 */
59 int tin_errno;
60
61 /* How many chars we read at last tin_read() */
62 static int offset = 0;
63
64 /*
65 * local prototypes
66 */
67 static char *tin_read(char *buffer, size_t len, FILE *fp, t_bool header);
68
69
70 #ifdef HAVE_SELECT
71 /*
72 * Used by the I/O read routine to look for keyboard input
73 * Returns TRUE if user aborted with 'q' or 'z' (lynx-style)
74 * FALSE otherwise
75 * TODO: document 'z' (, and allow it's remapping?) and 'Q'
76 * add a !HAVE_SELECT code path
77 */
78 t_bool
79 wait_for_input(
80 void)
81 {
82 int nfds, ch;
83 fd_set readfds;
84 struct timeval tv;
85
86 /*
87 * Main loop. Wait for input from keyboard or file or for a timeout.
88 */
89 forever {
90 FD_ZERO(&readfds);
91 FD_SET(STDIN_FILENO, &readfds);
92 /* FD_SET(fileno(NEED_REAL_NNTP_FD_HERE), &readfds); */
93
94 tv.tv_sec = 0; /* NNTP_READ_TIMEOUT; */
95 tv.tv_usec = 0;
96
97 /* DEBUG_IO((stderr, "waiting on %d and %d...", STDIN_FILENO, fileno(fd))); */
98 # ifdef HAVE_SELECT_INTP
99 if ((nfds = select(STDIN_FILENO + 1, (int *) &readfds, NULL, NULL, &tv)) == -1)
100 # else
101 if ((nfds = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv)) == -1)
102 # endif /* HAVE_SELECT_INTP */
103 {
104 if (errno != EINTR) {
105 perror_message("select() failed");
106 free(tin_progname);
107 giveup();
108 } else
109 return FALSE;
110 }
111
112 /* No input pending */
113 if (nfds == 0)
114 return FALSE;
115
116 /*
117 * Something is waiting. See what's cooking...
118 */
119 if (nfds > 0) {
120 /*
121 * User pressed something. If 'q'uit, then handle this. Process
122 * user input 1st so they get chance to quit on busy (or stalled)
123 * reads
124 */
125 if (FD_ISSET(STDIN_FILENO, &readfds)) {
126 if ((ch = ReadCh()) == EOF)
127 return FALSE;
128
129 /*
130 * check if keymap key was pressed. Unfortunately, keymap keys
131 * are encoded by a sequence of bytes starting with ESC, so we
132 * must first see if it was really an ESC or a keymap key before
133 * asking the user if he wants to abort.
134 */
135 if (ch == iKeyAbort) {
136 int keymap_ch = get_arrow_key(ch);
137
138 if (keymap_ch != KEYMAP_UNKNOWN)
139 ch = keymap_ch;
140 }
141
142 if (ch == iKeyQuit || ch == 'z' || ch == iKeyAbort) {
143 if (post_article_and_exit)
144 return FALSE;
145 if (prompt_yn(_(txt_read_abort), FALSE) == 1)
146 return TRUE;
147 }
148
149 if (ch == iKeyQuitTin) {
150 if (post_article_and_exit)
151 return FALSE;
152 if (prompt_yn(_(txt_read_exit), FALSE) == 1)
153 tin_done(EXIT_SUCCESS, NULL);
154 }
155
156 }
157
158 # if 0
159 /*
160 * Our file has something for us to read
161 */
162 if (FD_ISSET(fileno(NEED_NNTP_FD_HERE), &readfds))
163 return TRUE;
164 # endif /* 0 */
165 }
166
167 }
168 }
169 #endif /* HAVE_SELECT */
170
171
172 /*
173 * Support routine to read a fixed size buffer. This does most of the
174 * hard work for tin_fgets()
175 */
176 static t_bool partial_read;
177
178
179 static char *
180 tin_read(
181 char *buffer,
182 size_t len,
183 FILE *fp,
184 t_bool header)
185 {
186 char *ptr;
187 int c;
188 int i;
189 #ifdef NNTP_ABLE
190 t_bool check_dot_only_line;
191
192 /*
193 * We have to check '.' line when reading via NNTP and
194 * reading first line.
195 */
196 check_dot_only_line = (header && fp == FAKE_NNTP_FP && partial_read == FALSE);
197 #endif /* NNTP_ABLE */
198
199 partial_read = FALSE;
200
201 #ifdef NNTP_ABLE
202 # ifdef HAVE_SELECT
203 if (wait_for_input()) { /* Check if okay to read */
204 info_message(_("Aborting read, please wait..."));
205 drain_buffer(fp);
206 clear_message();
207 tin_errno = TIN_ABORT;
208 /* fflush(stdin); */
209 return NULL;
210 }
211 # endif /* HAVE_SELECT */
212
213 errno = 0; /* To check errno after read, clear it here */
214
215 /*
216 * Initially try and fit into supplied buffer
217 */
218 if (fp == FAKE_NNTP_FP)
219 ptr = get_server(buffer, (int) len);
220 else
221 ptr = fgets(buffer, (int) len, fp);
222 #else
223 errno = 0; /* To check errno after read, clear it here */
224
225 ptr = fgets(buffer, len, fp);
226 #endif /* NNTP_ABLE */
227
228 /* TODO: develop this next line? */
229 #ifdef DEBUG
230 if (errno && (debug & DEBUG_MISC))
231 fprintf(stderr, "tin_read(%s)", strerror(errno));
232 #endif /* DEBUG */
233
234 if (ptr == NULL) /* End of data? */
235 return NULL;
236
237 /*
238 * Was this only a partial read?
239 * We strip trailing \r and \n here and here _only_
240 * 'offset' is the # of chars which we read now
241 */
242 i = (int) strlen(buffer);
243 if (i >= 1 && buffer[i - 1] == '\n') {
244
245 if (i >= 2 && buffer[i - 2] == '\r') {
246 buffer[i - 2] = '\0';
247 offset = i -= 2;
248 } else {
249 buffer[i - 1] = '\0';
250 offset = --i;
251 }
252
253 /*
254 * If we're looking for continuation headers, mark this as a partial
255 * read and put back a newline. Unfolding (removing of this newline
256 * and whitespace, if necessary) must be done at a higher level --
257 * there are headers where whitespace is significant even in folded
258 * lines.
259 */
260 #ifdef NNTP_ABLE
261 if (check_dot_only_line && i == 1 && buffer[0] == '.') { /* EMPTY */
262 /* Find a terminator, don't check next line. */
263 } else
264 #endif /* NNTP_ABLE */
265 {
266 if (header) {
267 if (!i) { /* EMPTY */
268 /* Find a header separator, don't check next line. */
269 } else {
270 #ifdef NNTP_ABLE
271 if (fp == FAKE_NNTP_FP)
272 c = fgetc_server(fp);
273 else
274 #endif /* NNTP_ABLE */
275 c = fgetc(fp);
276 if (c == ' ' || c == '\t') {
277 partial_read = TRUE;
278 /* This is safe because we removed at least one char above */
279 buffer[offset++] = '\n';
280 buffer[offset] = '\0';
281 }
282
283 /* Push back the 1st char of next line */
284 if (c != EOF) {
285 #ifdef NNTP_ABLE
286 if (fp == FAKE_NNTP_FP)
287 ungetc_server(c, fp);
288 else
289 #endif /* NNTP_ABLE */
290 ungetc(c, fp);
291 }
292 }
293 }
294 }
295 } else {
296 partial_read = TRUE;
297 offset = i;
298 }
299
300 return buffer;
301 }
302
303
304 /*
305 * This is the main routine for reading news data from local spool or NNTP.
306 * It can handle arbitrary length lines of data, failed connections and
307 * user initiated aborts (where possible)
308 *
309 * We simply request data from an fd and data is read up to the next \n
310 * Any trailing \r and \n will be stripped.
311 * If fp is FAKE_NNTP_FP, then we are reading via a socket to an NNTP
312 * server. The required post-processing of the data will be done such that
313 * we look like a local read to the calling function.
314 *
315 * Header lines: If header is TRUE, then we assume we're reading a news
316 * article header. In some cases, article headers are split over multiple
317 * lines. The rule is that if the next line starts with \t or ' ', then it
318 * will be included as part of the current line. Line breaks are NOT
319 * stripped (but replaced by \n) in continuated lines except the trailing
320 * one; unfolding MUST be done at a higher level because it may be
321 * significant or not.
322 *
323 * Dynamic read code based on code by <emcmanus@gr.osf.org>
324 *
325 * Caveat: We try to keep the code path for a trivial read as short as
326 * possible.
327 */
328 char *
329 tin_fgets(
330 FILE *fp,
331 t_bool header)
332 {
333 static char *dynbuf = NULL;
334 static int size = 0;
335
336 int next;
337
338 tin_errno = 0; /* Clear errors */
339 partial_read = FALSE;
340
341 #if 1
342 if (fp == NULL) {
343 FreeAndNull(dynbuf);
344 return NULL;
345 }
346 /* Allocate initial buffer */
347 if (dynbuf == NULL) {
348 dynbuf = my_malloc(INIT * sizeof(*dynbuf));
349 size = INIT;
350 }
351 /* Otherwise reuse last buffer */
352 /* TODO: Should we free too large buffer? */
353 #else
354 FreeIfNeeded(dynbuf); /* Free any previous allocation */
355 dynbuf = my_malloc(INIT * sizeof(*dynbuf));
356 size = INIT;
357 #endif /* 1 */
358
359 if (tin_read(dynbuf, (size_t) size, fp, header) == NULL)
360 return NULL;
361
362 if (tin_errno != 0) {
363 DEBUG_IO((stderr, _("Aborted read\n")));
364 return NULL;
365 }
366
367 next = offset;
368
369 while (partial_read) {
370 if (next + RCHUNK > size)
371 size = next + RCHUNK;
372 dynbuf = my_realloc(dynbuf, (size_t) size * sizeof(*dynbuf));
373 (void) tin_read(dynbuf + next, (size_t) (size - next), fp, header); /* What if == NULL? */
374 next += offset;
375
376 if (tin_errno != 0)
377 return NULL;
378 }
379
380 /*
381 * Do processing of leading . for NNTP
382 * This only occurs at the start of lines
383 * At this point, dynbuf won't be NULL
384 */
385 #ifdef NNTP_ABLE
386 if (fp == FAKE_NNTP_FP) {
387 if (dynbuf[0] == '.') { /* reduce leading .'s */
388 if (dynbuf[1] == '\0') {
389 DEBUG_IO((stderr, "tin_fgets(NULL)\n"));
390 return NULL;
391 }
392 DEBUG_IO((stderr, "tin_fgets(%s)\n", dynbuf + 1));
393 return (dynbuf + 1);
394 }
395 }
396 #endif /* NNTP_ABLE */
397
398 DEBUG_IO((stderr, "tin_fgets(%s)\n", (dynbuf) ? dynbuf : "NULL"));
399
400 return dynbuf;
401 }
402
403
404 /*
405 * We can't just stop reading a socket once we are through with it. This
406 * drains out any pending data on the NNTP port
407 */
408 #ifdef NNTP_ABLE
409 void
410 drain_buffer(
411 FILE *fp)
412 {
413 int i = 0;
414
415 if (fp != FAKE_NNTP_FP)
416 return;
417
418 DEBUG_IO((stderr, _("Draining\n")));
419 while (tin_fgets(fp, FALSE) != NULL) {
420 if (++i % MODULO_COUNT_NUM == 0)
421 spin_cursor();
422 }
423 }
424 #endif /* NNTP_ABLE */
425
426 /* end of read.c */