1238730Sdelphij/*
2330571Sdelphij * Copyright (C) 1984-2017  Mark Nudelman
3238730Sdelphij *
4238730Sdelphij * You may distribute under the terms of either the GNU General Public
5238730Sdelphij * License or the Less License, as specified in the README file.
6238730Sdelphij *
7238730Sdelphij * For more information, see the README file.
8238730Sdelphij */
960786Sps
1060786Sps
1160786Sps/*
1260786Sps * An IFILE represents an input file.
1360786Sps *
1460786Sps * It is actually a pointer to an ifile structure,
1560786Sps * but is opaque outside this module.
1660786Sps * Ifile structures are kept in a linked list in the order they
1760786Sps * appear on the command line.
1860786Sps * Any new file which does not already appear in the list is
1960786Sps * inserted after the current file.
2060786Sps */
2160786Sps
2260786Sps#include "less.h"
2360786Sps
2460786Spsextern IFILE	curr_ifile;
2560786Sps
2660786Spsstruct ifile {
27330571Sdelphij	struct ifile *h_next;           /* Links for command line list */
2860786Sps	struct ifile *h_prev;
29330571Sdelphij	char *h_filename;               /* Name of the file */
30330571Sdelphij	void *h_filestate;              /* File state (used in ch.c) */
31330571Sdelphij	int h_index;                    /* Index within command line list */
32330571Sdelphij	int h_hold;                     /* Hold count */
33330571Sdelphij	char h_opened;                  /* Has this ifile been opened? */
34330571Sdelphij	struct scrpos h_scrpos;         /* Saved position within the file */
35330571Sdelphij	void *h_altpipe;                /* Alt pipe */
36330571Sdelphij	char *h_altfilename;            /* Alt filename */
3760786Sps};
3860786Sps
3960786Sps/*
4060786Sps * Convert an IFILE (external representation)
4160786Sps * to a struct file (internal representation), and vice versa.
4260786Sps */
4360786Sps#define int_ifile(h)	((struct ifile *)(h))
4460786Sps#define ext_ifile(h)	((IFILE)(h))
4560786Sps
4660786Sps/*
4760786Sps * Anchor for linked list.
4860786Sps */
4960786Spsstatic struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0',
5060786Sps				{ NULL_POSITION, 0 } };
5160786Spsstatic int ifiles = 0;
5260786Sps
5360786Sps	static void
5460786Spsincr_index(p, incr)
55330571Sdelphij	struct ifile *p;
5660786Sps	int incr;
5760786Sps{
5860786Sps	for (;  p != &anchor;  p = p->h_next)
5960786Sps		p->h_index += incr;
6060786Sps}
6160786Sps
6260786Sps/*
6360786Sps * Link an ifile into the ifile list.
6460786Sps */
6560786Sps	static void
6660786Spslink_ifile(p, prev)
6760786Sps	struct ifile *p;
6860786Sps	struct ifile *prev;
6960786Sps{
7060786Sps	/*
7160786Sps	 * Link into list.
7260786Sps	 */
7360786Sps	if (prev == NULL)
7460786Sps		prev = &anchor;
7560786Sps	p->h_next = prev->h_next;
7660786Sps	p->h_prev = prev;
7760786Sps	prev->h_next->h_prev = p;
7860786Sps	prev->h_next = p;
7960786Sps	/*
8060786Sps	 * Calculate index for the new one,
8160786Sps	 * and adjust the indexes for subsequent ifiles in the list.
8260786Sps	 */
8360786Sps	p->h_index = prev->h_index + 1;
8460786Sps	incr_index(p->h_next, 1);
8560786Sps	ifiles++;
8660786Sps}
8760786Sps
8860786Sps/*
8960786Sps * Unlink an ifile from the ifile list.
9060786Sps */
9160786Sps	static void
9260786Spsunlink_ifile(p)
9360786Sps	struct ifile *p;
9460786Sps{
9560786Sps	p->h_next->h_prev = p->h_prev;
9660786Sps	p->h_prev->h_next = p->h_next;
9760786Sps	incr_index(p->h_next, -1);
9860786Sps	ifiles--;
9960786Sps}
10060786Sps
10160786Sps/*
10260786Sps * Allocate a new ifile structure and stick a filename in it.
10360786Sps * It should go after "prev" in the list
10460786Sps * (or at the beginning of the list if "prev" is NULL).
10560786Sps * Return a pointer to the new ifile structure.
10660786Sps */
10760786Sps	static struct ifile *
10860786Spsnew_ifile(filename, prev)
10960786Sps	char *filename;
11060786Sps	struct ifile *prev;
11160786Sps{
112330571Sdelphij	struct ifile *p;
11360786Sps
11460786Sps	/*
11560786Sps	 * Allocate and initialize structure.
11660786Sps	 */
11760786Sps	p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
11860786Sps	p->h_filename = save(filename);
11960786Sps	p->h_scrpos.pos = NULL_POSITION;
12060786Sps	p->h_opened = 0;
12160786Sps	p->h_hold = 0;
12260786Sps	p->h_filestate = NULL;
12360786Sps	link_ifile(p, prev);
12460786Sps	return (p);
12560786Sps}
12660786Sps
12760786Sps/*
12860786Sps * Delete an existing ifile structure.
12960786Sps */
13060786Sps	public void
13160786Spsdel_ifile(h)
13260786Sps	IFILE h;
13360786Sps{
134330571Sdelphij	struct ifile *p;
13560786Sps
13660786Sps	if (h == NULL_IFILE)
13760786Sps		return;
13860786Sps	/*
13960786Sps	 * If the ifile we're deleting is the currently open ifile,
14060786Sps	 * move off it.
14160786Sps	 */
14260786Sps	unmark(h);
14360786Sps	if (h == curr_ifile)
14460786Sps		curr_ifile = getoff_ifile(curr_ifile);
14560786Sps	p = int_ifile(h);
14660786Sps	unlink_ifile(p);
14760786Sps	free(p->h_filename);
14860786Sps	free(p);
14960786Sps}
15060786Sps
15160786Sps/*
15260786Sps * Get the ifile after a given one in the list.
15360786Sps */
15460786Sps	public IFILE
15560786Spsnext_ifile(h)
15660786Sps	IFILE h;
15760786Sps{
158330571Sdelphij	struct ifile *p;
15960786Sps
16060786Sps	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
16160786Sps	if (p->h_next == &anchor)
16260786Sps		return (NULL_IFILE);
16360786Sps	return (ext_ifile(p->h_next));
16460786Sps}
16560786Sps
16660786Sps/*
16760786Sps * Get the ifile before a given one in the list.
16860786Sps */
16960786Sps	public IFILE
17060786Spsprev_ifile(h)
17160786Sps	IFILE h;
17260786Sps{
173330571Sdelphij	struct ifile *p;
17460786Sps
17560786Sps	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
17660786Sps	if (p->h_prev == &anchor)
17760786Sps		return (NULL_IFILE);
17860786Sps	return (ext_ifile(p->h_prev));
17960786Sps}
18060786Sps
18160786Sps/*
18260786Sps * Return a different ifile from the given one.
18360786Sps */
18460786Sps	public IFILE
18560786Spsgetoff_ifile(ifile)
18660786Sps	IFILE ifile;
18760786Sps{
18860786Sps	IFILE newifile;
18960786Sps
19060786Sps	if ((newifile = prev_ifile(ifile)) != NULL_IFILE)
19160786Sps		return (newifile);
19260786Sps	if ((newifile = next_ifile(ifile)) != NULL_IFILE)
19360786Sps		return (newifile);
19460786Sps	return (NULL_IFILE);
19560786Sps}
19660786Sps
19760786Sps/*
19860786Sps * Return the number of ifiles.
19960786Sps */
20060786Sps	public int
20160786Spsnifile()
20260786Sps{
20360786Sps	return (ifiles);
20460786Sps}
20560786Sps
20660786Sps/*
20760786Sps * Find an ifile structure, given a filename.
20860786Sps */
20960786Sps	static struct ifile *
21060786Spsfind_ifile(filename)
21160786Sps	char *filename;
21260786Sps{
213330571Sdelphij	struct ifile *p;
21460786Sps
21560786Sps	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
21660786Sps		if (strcmp(filename, p->h_filename) == 0)
21760786Sps			return (p);
21860786Sps	return (NULL);
21960786Sps}
22060786Sps
22160786Sps/*
22260786Sps * Get the ifile associated with a filename.
22360786Sps * If the filename has not been seen before,
22460786Sps * insert the new ifile after "prev" in the list.
22560786Sps */
22660786Sps	public IFILE
22760786Spsget_ifile(filename, prev)
22860786Sps	char *filename;
22960786Sps	IFILE prev;
23060786Sps{
231330571Sdelphij	struct ifile *p;
23260786Sps
23360786Sps	if ((p = find_ifile(filename)) == NULL)
23460786Sps		p = new_ifile(filename, int_ifile(prev));
23560786Sps	return (ext_ifile(p));
23660786Sps}
23760786Sps
23860786Sps/*
23960786Sps * Get the filename associated with a ifile.
24060786Sps */
24160786Sps	public char *
24260786Spsget_filename(ifile)
24360786Sps	IFILE ifile;
24460786Sps{
24560786Sps	if (ifile == NULL)
24660786Sps		return (NULL);
24760786Sps	return (int_ifile(ifile)->h_filename);
24860786Sps}
24960786Sps
25060786Sps/*
25160786Sps * Get the index of the file associated with a ifile.
25260786Sps */
25360786Sps	public int
25460786Spsget_index(ifile)
25560786Sps	IFILE ifile;
25660786Sps{
25760786Sps	return (int_ifile(ifile)->h_index);
25860786Sps}
25960786Sps
26060786Sps/*
26160786Sps * Save the file position to be associated with a given file.
26260786Sps */
26360786Sps	public void
26460786Spsstore_pos(ifile, scrpos)
26560786Sps	IFILE ifile;
26660786Sps	struct scrpos *scrpos;
26760786Sps{
26860786Sps	int_ifile(ifile)->h_scrpos = *scrpos;
26960786Sps}
27060786Sps
27160786Sps/*
27260786Sps * Recall the file position associated with a file.
27360786Sps * If no position has been associated with the file, return NULL_POSITION.
27460786Sps */
27560786Sps	public void
27660786Spsget_pos(ifile, scrpos)
27760786Sps	IFILE ifile;
27860786Sps	struct scrpos *scrpos;
27960786Sps{
28060786Sps	*scrpos = int_ifile(ifile)->h_scrpos;
28160786Sps}
28260786Sps
28360786Sps/*
28460786Sps * Mark the ifile as "opened".
28560786Sps */
28660786Sps	public void
28760786Spsset_open(ifile)
28860786Sps	IFILE ifile;
28960786Sps{
29060786Sps	int_ifile(ifile)->h_opened = 1;
29160786Sps}
29260786Sps
29360786Sps/*
29460786Sps * Return whether the ifile has been opened previously.
29560786Sps */
29660786Sps	public int
29760786Spsopened(ifile)
29860786Sps	IFILE ifile;
29960786Sps{
30060786Sps	return (int_ifile(ifile)->h_opened);
30160786Sps}
30260786Sps
30360786Sps	public void
30460786Spshold_ifile(ifile, incr)
30560786Sps	IFILE ifile;
30660786Sps	int incr;
30760786Sps{
30860786Sps	int_ifile(ifile)->h_hold += incr;
30960786Sps}
31060786Sps
31160786Sps	public int
31260786Spsheld_ifile(ifile)
31360786Sps	IFILE ifile;
31460786Sps{
31560786Sps	return (int_ifile(ifile)->h_hold);
31660786Sps}
31760786Sps
31860786Sps	public void *
31960786Spsget_filestate(ifile)
32060786Sps	IFILE ifile;
32160786Sps{
32260786Sps	return (int_ifile(ifile)->h_filestate);
32360786Sps}
32460786Sps
32560786Sps	public void
32660786Spsset_filestate(ifile, filestate)
32760786Sps	IFILE ifile;
32860786Sps	void *filestate;
32960786Sps{
33060786Sps	int_ifile(ifile)->h_filestate = filestate;
33160786Sps}
33260786Sps
333330571Sdelphij	public void
334330571Sdelphijset_altpipe(ifile, p)
335330571Sdelphij	IFILE ifile;
336330571Sdelphij	void *p;
337330571Sdelphij{
338330571Sdelphij	int_ifile(ifile)->h_altpipe = p;
339330571Sdelphij}
340330571Sdelphij
341330571Sdelphij	public void *
342330571Sdelphijget_altpipe(ifile)
343330571Sdelphij	IFILE ifile;
344330571Sdelphij{
345330571Sdelphij	return (int_ifile(ifile)->h_altpipe);
346330571Sdelphij}
347330571Sdelphij
348330571Sdelphij	public void
349330571Sdelphijset_altfilename(ifile, altfilename)
350330571Sdelphij	IFILE ifile;
351330571Sdelphij	char *altfilename;
352330571Sdelphij{
353330571Sdelphij	struct ifile *p = int_ifile(ifile);
354330571Sdelphij	if (p->h_altfilename != NULL)
355330571Sdelphij		free(p->h_altfilename);
356330571Sdelphij	p->h_altfilename = altfilename;
357330571Sdelphij}
358330571Sdelphij
359330571Sdelphij	public char *
360330571Sdelphijget_altfilename(ifile)
361330571Sdelphij	IFILE ifile;
362330571Sdelphij{
363330571Sdelphij	return (int_ifile(ifile)->h_altfilename);
364330571Sdelphij}
365330571Sdelphij
36660786Sps#if 0
36760786Sps	public void
36860786Spsif_dump()
36960786Sps{
370330571Sdelphij	struct ifile *p;
37160786Sps
37260786Sps	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
37360786Sps	{
37460786Sps		printf("%x: %d. <%s> pos %d,%x\n",
37560786Sps			p, p->h_index, p->h_filename,
37660786Sps			p->h_scrpos.ln, p->h_scrpos.pos);
37760786Sps		ch_dump(p->h_filestate);
37860786Sps	}
37960786Sps}
38060786Sps#endif
381