GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../ch.c Lines: 187 273 68.5 %
Date: 2017-11-07 Branches: 108 196 55.1 %

Line Branch Exec Source
1
/*
2
 * Copyright (C) 1984-2012  Mark Nudelman
3
 * Modified for use with illumos by Garrett D'Amore.
4
 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
5
 *
6
 * You may distribute under the terms of either the GNU General Public
7
 * License or the Less License, as specified in the README file.
8
 *
9
 * For more information, see the README file.
10
 */
11
12
/*
13
 * Low level character input from the input file.
14
 * We use these special purpose routines which optimize moving
15
 * both forward and backward from the current read pointer.
16
 */
17
18
#include <sys/stat.h>
19
20
#include "less.h"
21
22
extern dev_t curr_dev;
23
extern ino_t curr_ino;
24
extern int less_is_more;
25
26
typedef off_t BLOCKNUM;
27
28
int ignore_eoi;
29
30
/*
31
 * Pool of buffers holding the most recently used blocks of the input file.
32
 * The buffer pool is kept as a doubly-linked circular list,
33
 * in order from most- to least-recently used.
34
 * The circular list is anchored by the file state "thisfile".
35
 */
36
struct bufnode {
37
	struct bufnode *next, *prev;
38
	struct bufnode *hnext, *hprev;
39
};
40
41
#define	LBUFSIZE	8192
42
struct buf {
43
	struct bufnode node;
44
	BLOCKNUM block;
45
	unsigned int datasize;
46
	unsigned char data[LBUFSIZE];
47
};
48
#define	bufnode_buf(bn)  ((struct buf *)bn)
49
50
/*
51
 * The file state is maintained in a filestate structure.
52
 * A pointer to the filestate is kept in the ifile structure.
53
 */
54
#define	BUFHASH_SIZE	64
55
struct filestate {
56
	struct bufnode buflist;
57
	struct bufnode hashtbl[BUFHASH_SIZE];
58
	int file;
59
	int flags;
60
	off_t fpos;
61
	int nbufs;
62
	BLOCKNUM block;
63
	unsigned int offset;
64
	off_t fsize;
65
};
66
67
#define	ch_bufhead	thisfile->buflist.next
68
#define	ch_buftail	thisfile->buflist.prev
69
#define	ch_nbufs	thisfile->nbufs
70
#define	ch_block	thisfile->block
71
#define	ch_offset	thisfile->offset
72
#define	ch_fpos		thisfile->fpos
73
#define	ch_fsize	thisfile->fsize
74
#define	ch_flags	thisfile->flags
75
#define	ch_file		thisfile->file
76
77
#define	END_OF_CHAIN	(&thisfile->buflist)
78
#define	END_OF_HCHAIN(h) (&thisfile->hashtbl[h])
79
#define	BUFHASH(blk)	((blk) & (BUFHASH_SIZE-1))
80
81
/*
82
 * Macros to manipulate the list of buffers in thisfile->buflist.
83
 */
84
#define	FOR_BUFS(bn) \
85
	for ((bn) = ch_bufhead; (bn) != END_OF_CHAIN; (bn) = (bn)->next)
86
87
#define	BUF_RM(bn) \
88
	(bn)->next->prev = (bn)->prev; \
89
	(bn)->prev->next = (bn)->next;
90
91
#define	BUF_INS_HEAD(bn) \
92
	(bn)->next = ch_bufhead; \
93
	(bn)->prev = END_OF_CHAIN; \
94
	ch_bufhead->prev = (bn); \
95
	ch_bufhead = (bn);
96
97
#define	BUF_INS_TAIL(bn) \
98
	(bn)->next = END_OF_CHAIN; \
99
	(bn)->prev = ch_buftail; \
100
	ch_buftail->next = (bn); \
101
	ch_buftail = (bn);
102
103
/*
104
 * Macros to manipulate the list of buffers in thisfile->hashtbl[n].
105
 */
106
#define	FOR_BUFS_IN_CHAIN(h, bn) \
107
	for ((bn) = thisfile->hashtbl[h].hnext; \
108
	    (bn) != END_OF_HCHAIN(h); (bn) = (bn)->hnext)
109
110
#define	BUF_HASH_RM(bn) \
111
	(bn)->hnext->hprev = (bn)->hprev; \
112
	(bn)->hprev->hnext = (bn)->hnext;
113
114
#define	BUF_HASH_INS(bn, h) \
115
	(bn)->hnext = thisfile->hashtbl[h].hnext; \
116
	(bn)->hprev = END_OF_HCHAIN(h); \
117
	thisfile->hashtbl[h].hnext->hprev = (bn); \
118
	thisfile->hashtbl[h].hnext = (bn);
119
120
static struct filestate *thisfile;
121
static int ch_ungotchar = -1;
122
static int maxbufs = -1;
123
124
extern int autobuf;
125
extern volatile sig_atomic_t sigs;
126
extern int secure;
127
extern int screen_trashed;
128
extern int follow_mode;
129
extern IFILE curr_ifile;
130
extern int logfile;
131
extern char *namelogfile;
132
133
static int ch_addbuf(void);
134
135
136
/*
137
 * Get the character pointed to by the read pointer.
138
 */
139
int
140
ch_get(void)
141
{
142
	struct buf *bp;
143
	struct bufnode *bn;
144
	int n;
145
	int slept;
146
	int h;
147
	off_t pos;
148
	off_t len;
149
150
19826190
	if (thisfile == NULL)
151
		return (EOI);
152
153
	/*
154
	 * Quick check for the common case where
155
	 * the desired char is in the head buffer.
156
	 */
157
9913095
	if (ch_bufhead != END_OF_CHAIN) {
158
9913058
		bp = bufnode_buf(ch_bufhead);
159

19824563
		if (ch_block == bp->block && ch_offset < bp->datasize)
160
9911448
			return (bp->data[ch_offset]);
161
	}
162
163
	slept = FALSE;
164
165
	/*
166
	 * Look for a buffer holding the desired block.
167
	 */
168
1647
	h = BUFHASH(ch_block);
169
3294
	FOR_BUFS_IN_CHAIN(h, bn) {
170
1352
		bp = bufnode_buf(bn);
171
1352
		if (bp->block == ch_block) {
172
1352
			if (ch_offset >= bp->datasize)
173
				/*
174
				 * Need more data in this buffer.
175
				 */
176
				break;
177
			goto found;
178
		}
179
	}
180
352
	if (bn == END_OF_HCHAIN(h)) {
181
		/*
182
		 * Block is not in a buffer.
183
		 * Take the least recently used buffer
184
		 * and read the desired block into it.
185
		 * If the LRU buffer has data in it,
186
		 * then maybe allocate a new buffer.
187
		 */
188

553
		if (ch_buftail == END_OF_CHAIN ||
189
258
		    bufnode_buf(ch_buftail)->block != -1) {
190
			/*
191
			 * There is no empty buffer to use.
192
			 * Allocate a new buffer if:
193
			 * 1. We can't seek on this file and -b is not in
194
			 *    effect; or
195
			 * 2. We haven't allocated the max buffers for this
196
			 *    file yet.
197
			 */
198

1135
			if ((autobuf && !(ch_flags & CH_CANSEEK)) ||
199
545
			    (maxbufs < 0 || ch_nbufs < maxbufs))
200
84
				if (ch_addbuf())
201
					/*
202
					 * Allocation failed: turn off autobuf.
203
					 */
204
					autobuf = OPT_OFF;
205
		}
206
295
		bn = ch_buftail;
207
295
		bp = bufnode_buf(bn);
208
295
		BUF_HASH_RM(bn); /* Remove from old hash chain. */
209
295
		bp->block = ch_block;
210
295
		bp->datasize = 0;
211
295
		BUF_HASH_INS(bn, h); /* Insert into new hash chain. */
212
295
	}
213
214
read_more:
215
358
	pos = (ch_block * LBUFSIZE) + bp->datasize;
216

665
	if ((len = ch_length()) != -1 && pos >= len)
217
		/*
218
		 * At end of file.
219
		 */
220
57
		return (EOI);
221
222
301
	if (pos != ch_fpos) {
223
		/*
224
		 * Not at the correct position: must seek.
225
		 * If input is a pipe, we're in trouble (can't seek on a pipe).
226
		 * Some data has been lost: just return "?".
227
		 */
228
2
		if (!(ch_flags & CH_CANSEEK))
229
			return ('?');
230
2
		if (lseek(ch_file, (off_t)pos, SEEK_SET) == (off_t)-1) {
231
			error("seek error", NULL);
232
			clear_eol();
233
			return (EOI);
234
		}
235
2
		ch_fpos = pos;
236
2
	}
237
238
	/*
239
	 * Read the block.
240
	 * If we read less than a full block, that's ok.
241
	 * We use partial block and pick up the rest next time.
242
	 */
243
301
	if (ch_ungotchar != -1) {
244
		bp->data[bp->datasize] = (unsigned char)ch_ungotchar;
245
		n = 1;
246
		ch_ungotchar = -1;
247
	} else {
248
602
		n = iread(ch_file, &bp->data[bp->datasize],
249
301
		    (unsigned int)(LBUFSIZE - bp->datasize));
250
	}
251
252
301
	if (n == READ_INTR)
253
		return (EOI);
254
301
	if (n < 0) {
255
		error("read error", NULL);
256
		clear_eol();
257
		n = 0;
258
	}
259
260
	/*
261
	 * If we have a log file, write the new data to it.
262
	 */
263
301
	if (!secure && logfile >= 0 && n > 0)
264
		(void) write(logfile, (char *)&bp->data[bp->datasize], n);
265
266
301
	ch_fpos += n;
267
301
	bp->datasize += n;
268
269
	/*
270
	 * If we have read to end of file, set ch_fsize to indicate
271
	 * the position of the end of file.
272
	 */
273
301
	if (n == 0) {
274
6
		ch_fsize = pos;
275
6
		if (ignore_eoi) {
276
			/*
277
			 * We are ignoring EOF.
278
			 * Wait a while, then try again.
279
			 */
280
			if (!slept) {
281
				PARG parg;
282
				parg.p_string = wait_message();
283
				ierror("%s", &parg);
284
			}
285
			sleep(1);
286
			slept = TRUE;
287
288
			if (follow_mode == FOLLOW_NAME) {
289
				/*
290
				 * See whether the file's i-number has changed.
291
				 * If so, force the file to be closed and
292
				 * reopened.
293
				 */
294
				struct stat st;
295
				int r = stat(get_filename(curr_ifile), &st);
296
				if (r == 0 && (st.st_ino != curr_ino ||
297
				    st.st_dev != curr_dev)) {
298
					/*
299
					 * screen_trashed=2 causes
300
					 * make_display to reopen the file.
301
					 */
302
					screen_trashed = 2;
303
					return (EOI);
304
				}
305
			}
306
		}
307
6
		if (sigs)
308
			return (EOI);
309
	}
310
311
found:
312
1596
	if (ch_bufhead != bn) {
313
		/*
314
		 * Move the buffer to the head of the buffer chain.
315
		 * This orders the buffer chain, most- to least-recently used.
316
		 */
317
1553
		BUF_RM(bn);
318
1553
		BUF_INS_HEAD(bn);
319
320
		/*
321
		 * Move to head of hash chain too.
322
		 */
323
1553
		BUF_HASH_RM(bn);
324
1553
		BUF_HASH_INS(bn, h);
325
1553
	}
326
327
1596
	if (ch_offset >= bp->datasize)
328
		/*
329
		 * After all that, we still don't have enough data.
330
		 * Go back and try again.
331
		 */
332
		goto read_more;
333
334
1590
	return (bp->data[ch_offset]);
335
9913095
}
336
337
/*
338
 * ch_ungetchar is a rather kludgy and limited way to push
339
 * a single char onto an input file descriptor.
340
 */
341
void
342
ch_ungetchar(int c)
343
{
344
68
	if (c != -1 && ch_ungotchar != -1)
345
		error("ch_ungetchar overrun", NULL);
346
34
	ch_ungotchar = c;
347
34
}
348
349
/*
350
 * Close the logfile.
351
 * If we haven't read all of standard input into it, do that now.
352
 */
353
void
354
end_logfile(void)
355
{
356
	static int tried = FALSE;
357
358
152
	if (logfile < 0)
359
		return;
360
	if (!tried && ch_fsize == -1) {
361
		tried = TRUE;
362
		ierror("Finishing logfile", NULL);
363
		while (ch_forw_get() != EOI)
364
			if (ABORT_SIGS())
365
				break;
366
	}
367
	close(logfile);
368
	logfile = -1;
369
	namelogfile = NULL;
370
76
}
371
372
/*
373
 * Start a log file AFTER less has already been running.
374
 * Invoked from the - command; see toggle_option().
375
 * Write all the existing buffered data to the log file.
376
 */
377
void
378
sync_logfile(void)
379
{
380
	struct buf *bp;
381
	struct bufnode *bn;
382
	int warned = FALSE;
383
	BLOCKNUM block;
384
	BLOCKNUM nblocks;
385
386
	nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;
387
	for (block = 0; block < nblocks; block++) {
388
		int wrote = FALSE;
389
		FOR_BUFS(bn) {
390
			bp = bufnode_buf(bn);
391
			if (bp->block == block) {
392
				(void) write(logfile, (char *)bp->data,
393
				    bp->datasize);
394
				wrote = TRUE;
395
				break;
396
			}
397
		}
398
		if (!wrote && !warned) {
399
			error("Warning: log file is incomplete", NULL);
400
			warned = TRUE;
401
		}
402
	}
403
}
404
405
/*
406
 * Determine if a specific block is currently in one of the buffers.
407
 */
408
static int
409
buffered(BLOCKNUM block)
410
{
411
	struct buf *bp;
412
	struct bufnode *bn;
413
	int h;
414
415
58670
	h = BUFHASH(block);
416
58670
	FOR_BUFS_IN_CHAIN(h, bn) {
417
29335
		bp = bufnode_buf(bn);
418
29335
		if (bp->block == block)
419
29335
			return (TRUE);
420
	}
421
	return (FALSE);
422
29335
}
423
424
/*
425
 * Seek to a specified position in the file.
426
 * Return 0 if successful, non-zero if can't seek there.
427
 */
428
int
429
ch_seek(off_t pos)
430
{
431
	BLOCKNUM new_block;
432
	off_t len;
433
434
222708
	if (thisfile == NULL)
435
		return (0);
436
437
111354
	len = ch_length();
438

315307
	if (pos < ch_zero() || (len != -1 && pos > len))
439
		return (1);
440
441
111354
	new_block = pos / LBUFSIZE;
442

170050
	if (!(ch_flags & CH_CANSEEK) && pos != ch_fpos &&
443
29327
	    !buffered(new_block)) {
444
		if (ch_fpos > pos)
445
			return (1);
446
		while (ch_fpos < pos) {
447
			if (ch_forw_get() == EOI)
448
				return (1);
449
			if (ABORT_SIGS())
450
				return (1);
451
		}
452
		return (0);
453
	}
454
	/*
455
	 * Set read pointer.
456
	 */
457
111354
	ch_block = new_block;
458
111354
	ch_offset = pos % LBUFSIZE;
459
111354
	return (0);
460
111354
}
461
462
/*
463
 * Seek to the end of the file.
464
 */
465
int
466
ch_end_seek(void)
467
{
468
	off_t len;
469
470
24
	if (thisfile == NULL)
471
		return (0);
472
473
12
	if (ch_flags & CH_CANSEEK)
474
4
		ch_fsize = filesize(ch_file);
475
476
12
	len = ch_length();
477
12
	if (len != -1)
478
7
		return (ch_seek(len));
479
480
	/*
481
	 * Do it the slow way: read till end of data.
482
	 */
483
90602
	while (ch_forw_get() != EOI)
484
90597
		if (ABORT_SIGS())
485
			return (1);
486
5
	return (0);
487
12
}
488
489
/*
490
 * Seek to the beginning of the file, or as close to it as we can get.
491
 * We may not be able to seek there if input is a pipe and the
492
 * beginning of the pipe is no longer buffered.
493
 */
494
int
495
ch_beg_seek(void)
496
{
497
	struct bufnode *bn;
498
	struct bufnode *firstbn;
499
500
	/*
501
	 * Try a plain ch_seek first.
502
	 */
503
	if (ch_seek(ch_zero()) == 0)
504
		return (0);
505
506
	/*
507
	 * Can't get to position 0.
508
	 * Look thru the buffers for the one closest to position 0.
509
	 */
510
	firstbn = ch_bufhead;
511
	if (firstbn == END_OF_CHAIN)
512
		return (1);
513
	FOR_BUFS(bn) {
514
		if (bufnode_buf(bn)->block < bufnode_buf(firstbn)->block)
515
			firstbn = bn;
516
	}
517
	ch_block = bufnode_buf(firstbn)->block;
518
	ch_offset = 0;
519
	return (0);
520
}
521
522
/*
523
 * Return the length of the file, if known.
524
 */
525
off_t
526
ch_length(void)
527
{
528
230590
	if (thisfile == NULL)
529
		return (-1);
530
115295
	if (ignore_eoi)
531
		return (-1);
532
115295
	if (ch_flags & CH_NODATA)
533
		return (0);
534
115295
	return (ch_fsize);
535
115295
}
536
537
/*
538
 * Return the current position in the file.
539
 */
540
off_t
541
ch_tell(void)
542
{
543
3653056
	if (thisfile == NULL)
544
		return (-1);
545
1826528
	return ((ch_block * LBUFSIZE) + ch_offset);
546
1826528
}
547
548
/*
549
 * Get the current char and post-increment the read pointer.
550
 */
551
int
552
ch_forw_get(void)
553
{
554
	int c;
555
556
14293682
	if (thisfile == NULL)
557
		return (EOI);
558
7146841
	c = ch_get();
559
7146841
	if (c == EOI)
560
57
		return (EOI);
561
7146784
	if (ch_offset < LBUFSIZE-1) {
562
7145898
		ch_offset++;
563
7145898
	} else {
564
886
		ch_block ++;
565
886
		ch_offset = 0;
566
	}
567
7146784
	return (c);
568
7146841
}
569
570
/*
571
 * Pre-decrement the read pointer and get the new current char.
572
 */
573
int
574
ch_back_get(void)
575
{
576
5532608
	if (thisfile == NULL)
577
		return (EOI);
578
2766304
	if (ch_offset > 0) {
579
2765901
		ch_offset --;
580
2765901
	} else {
581
403
		if (ch_block <= 0)
582
50
			return (EOI);
583

361
		if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1))
584
			return (EOI);
585
353
		ch_block--;
586
353
		ch_offset = LBUFSIZE-1;
587
	}
588
2766254
	return (ch_get());
589
2766304
}
590
591
/*
592
 * Set max amount of buffer space.
593
 * bufspace is in units of 1024 bytes.  -1 mean no limit.
594
 */
595
void
596
ch_setbufspace(int bufspace)
597
{
598
78
	if (bufspace < 0) {
599
		maxbufs = -1;
600
	} else {
601
39
		maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE;
602
39
		if (maxbufs < 1)
603
			maxbufs = 1;
604
	}
605
39
}
606
607
/*
608
 * Flush (discard) any saved file state, including buffer contents.
609
 */
610
void
611
ch_flush(void)
612
{
613
	struct bufnode *bn;
614
615
74
	if (thisfile == NULL)
616
		return;
617
618
37
	if (!(ch_flags & CH_CANSEEK)) {
619
		/*
620
		 * If input is a pipe, we don't flush buffer contents,
621
		 * since the contents can't be recovered.
622
		 */
623
12
		ch_fsize = -1;
624
12
		return;
625
	}
626
627
	/*
628
	 * Initialize all the buffers.
629
	 */
630
50
	FOR_BUFS(bn) {
631
		bufnode_buf(bn)->block = -1;
632
	}
633
634
	/*
635
	 * Figure out the size of the file, if we can.
636
	 */
637
25
	ch_fsize = filesize(ch_file);
638
639
	/*
640
	 * Seek to a known position: the beginning of the file.
641
	 */
642
25
	ch_fpos = 0;
643
25
	ch_block = 0; /* ch_fpos / LBUFSIZE; */
644
25
	ch_offset = 0; /* ch_fpos % LBUFSIZE; */
645
646
#if 1
647
	/*
648
	 * This is a kludge to workaround a Linux kernel bug: files in
649
	 * /proc have a size of 0 according to fstat() but have readable
650
	 * data.  They are sometimes, but not always, seekable.
651
	 * Force them to be non-seekable here.
652
	 */
653
25
	if (ch_fsize == 0) {
654
		ch_fsize = -1;
655
		ch_flags &= ~CH_CANSEEK;
656
	}
657
#endif
658
659
25
	if (lseek(ch_file, (off_t)0, SEEK_SET) == (off_t)-1) {
660
		/*
661
		 * Warning only; even if the seek fails for some reason,
662
		 * there's a good chance we're at the beginning anyway.
663
		 * {{ I think this is bogus reasoning. }}
664
		 */
665
		error("seek error to 0", NULL);
666
	}
667
62
}
668
669
/*
670
 * Allocate a new buffer.
671
 * The buffer is added to the tail of the buffer chain.
672
 */
673
static int
674
ch_addbuf(void)
675
{
676
	struct buf *bp;
677
	struct bufnode *bn;
678
679
	/*
680
	 * Allocate and initialize a new buffer and link it
681
	 * onto the tail of the buffer list.
682
	 */
683
168
	bp = calloc(1, sizeof (struct buf));
684
84
	if (bp == NULL)
685
		return (1);
686
84
	ch_nbufs++;
687
84
	bp->block = -1;
688
84
	bn = &bp->node;
689
690
84
	BUF_INS_TAIL(bn);
691
84
	BUF_HASH_INS(bn, 0);
692
84
	return (0);
693
84
}
694
695
/*
696
 *
697
 */
698
static void
699
init_hashtbl(void)
700
{
701
	int h;
702
703
8122
	for (h = 0; h < BUFHASH_SIZE; h++) {
704
3968
		thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h);
705
3968
		thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h);
706
	}
707
62
}
708
709
/*
710
 * Delete all buffers for this file.
711
 */
712
static void
713
ch_delbufs(void)
714
{
715
	struct bufnode *bn;
716
717
153
	while (ch_bufhead != END_OF_CHAIN) {
718
		bn = ch_bufhead;
719
39
		BUF_RM(bn);
720
39
		free(bufnode_buf(bn));
721
	}
722
25
	ch_nbufs = 0;
723
25
	init_hashtbl();
724
25
}
725
726
/*
727
 * Is it possible to seek on a file descriptor?
728
 */
729
int
730
seekable(int f)
731
{
732
100
	return (lseek(f, (off_t)1, SEEK_SET) != (off_t)-1);
733
}
734
735
/*
736
 * Force EOF to be at the current read position.
737
 * This is used after an ignore_eof read, during which the EOF may change.
738
 */
739
void
740
ch_set_eof(void)
741
{
742
	ch_fsize = ch_fpos;
743
}
744
745
746
/*
747
 * Initialize file state for a new file.
748
 */
749
void
750
ch_init(int f, int flags)
751
{
752
	/*
753
	 * See if we already have a filestate for this file.
754
	 */
755
74
	thisfile = get_filestate(curr_ifile);
756
37
	if (thisfile == NULL) {
757
		/*
758
		 * Allocate and initialize a new filestate.
759
		 */
760
37
		thisfile = calloc(1, sizeof (struct filestate));
761
37
		thisfile->buflist.next = thisfile->buflist.prev = END_OF_CHAIN;
762
37
		thisfile->nbufs = 0;
763
37
		thisfile->flags = 0;
764
37
		thisfile->fpos = 0;
765
37
		thisfile->block = 0;
766
37
		thisfile->offset = 0;
767
37
		thisfile->file = -1;
768
37
		thisfile->fsize = -1;
769
37
		ch_flags = flags;
770
37
		init_hashtbl();
771
		/*
772
		 * Try to seek; set CH_CANSEEK if it works.
773
		 */
774

62
		if ((flags & CH_CANSEEK) && !seekable(f))
775
			ch_flags &= ~CH_CANSEEK;
776
37
		set_filestate(curr_ifile, (void *) thisfile);
777
37
	}
778
37
	if (thisfile->file == -1)
779
37
		thisfile->file = f;
780
37
	ch_flush();
781
37
}
782
783
/*
784
 * Close a filestate.
785
 */
786
void
787
ch_close(void)
788
{
789
	int keepstate = FALSE;
790
791
74
	if (thisfile == NULL)
792
		return;
793
794
37
	if (ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE)) {
795
		/*
796
		 * We can seek or re-open, so we don't need to keep buffers.
797
		 */
798
25
		ch_delbufs();
799
25
	} else {
800
		keepstate = TRUE;
801
	}
802
37
	if (!(ch_flags & CH_KEEPOPEN)) {
803
		/*
804
		 * We don't need to keep the file descriptor open
805
		 * (because we can re-open it.)
806
		 * But don't really close it if it was opened via popen(),
807
		 * because pclose() wants to close it.
808
		 */
809
25
		if (!(ch_flags & CH_POPENED))
810
25
			close(ch_file);
811
25
		ch_file = -1;
812
25
	} else {
813
		keepstate = TRUE;
814
	}
815
37
	if (!keepstate) {
816
		/*
817
		 * We don't even need to keep the filestate structure.
818
		 */
819
25
		free(thisfile);
820
25
		thisfile = NULL;
821
25
		set_filestate(curr_ifile, NULL);
822
25
	}
823
74
}
824
825
/*
826
 * Return ch_flags for the current file.
827
 */
828
int
829
ch_getflags(void)
830
{
831
130188
	if (thisfile == NULL)
832
		return (0);
833
65094
	return (ch_flags);
834
65094
}