160786Sps/*
2240121Sdelphij * Copyright (C) 1984-2012  Mark Nudelman
360786Sps *
460786Sps * You may distribute under the terms of either the GNU General Public
560786Sps * License or the Less License, as specified in the README file.
660786Sps *
7240121Sdelphij * For more information, see the README file.
860786Sps */
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 {
2760786Sps	struct ifile *h_next;		/* Links for command line list */
2860786Sps	struct ifile *h_prev;
2960786Sps	char *h_filename;		/* Name of the file */
3060786Sps	void *h_filestate;		/* File state (used in ch.c) */
3160786Sps	int h_index;			/* Index within command line list */
3260786Sps	int h_hold;			/* Hold count */
3360786Sps	char h_opened;			/* Has this ifile been opened? */
3460786Sps	struct scrpos h_scrpos;		/* Saved position within the file */
3560786Sps};
3660786Sps
3760786Sps/*
3860786Sps * Convert an IFILE (external representation)
3960786Sps * to a struct file (internal representation), and vice versa.
4060786Sps */
4160786Sps#define int_ifile(h)	((struct ifile *)(h))
4260786Sps#define ext_ifile(h)	((IFILE)(h))
4360786Sps
4460786Sps/*
4560786Sps * Anchor for linked list.
4660786Sps */
4760786Spsstatic struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0',
4860786Sps				{ NULL_POSITION, 0 } };
4960786Spsstatic int ifiles = 0;
5060786Sps
5160786Sps	static void
5260786Spsincr_index(p, incr)
5360786Sps	register struct ifile *p;
5460786Sps	int incr;
5560786Sps{
5660786Sps	for (;  p != &anchor;  p = p->h_next)
5760786Sps		p->h_index += incr;
5860786Sps}
5960786Sps
6060786Sps/*
6160786Sps * Link an ifile into the ifile list.
6260786Sps */
6360786Sps	static void
6460786Spslink_ifile(p, prev)
6560786Sps	struct ifile *p;
6660786Sps	struct ifile *prev;
6760786Sps{
6860786Sps	/*
6960786Sps	 * Link into list.
7060786Sps	 */
7160786Sps	if (prev == NULL)
7260786Sps		prev = &anchor;
7360786Sps	p->h_next = prev->h_next;
7460786Sps	p->h_prev = prev;
7560786Sps	prev->h_next->h_prev = p;
7660786Sps	prev->h_next = p;
7760786Sps	/*
7860786Sps	 * Calculate index for the new one,
7960786Sps	 * and adjust the indexes for subsequent ifiles in the list.
8060786Sps	 */
8160786Sps	p->h_index = prev->h_index + 1;
8260786Sps	incr_index(p->h_next, 1);
8360786Sps	ifiles++;
8460786Sps}
8560786Sps
8660786Sps/*
8760786Sps * Unlink an ifile from the ifile list.
8860786Sps */
8960786Sps	static void
9060786Spsunlink_ifile(p)
9160786Sps	struct ifile *p;
9260786Sps{
9360786Sps	p->h_next->h_prev = p->h_prev;
9460786Sps	p->h_prev->h_next = p->h_next;
9560786Sps	incr_index(p->h_next, -1);
9660786Sps	ifiles--;
9760786Sps}
9860786Sps
9960786Sps/*
10060786Sps * Allocate a new ifile structure and stick a filename in it.
10160786Sps * It should go after "prev" in the list
10260786Sps * (or at the beginning of the list if "prev" is NULL).
10360786Sps * Return a pointer to the new ifile structure.
10460786Sps */
10560786Sps	static struct ifile *
10660786Spsnew_ifile(filename, prev)
10760786Sps	char *filename;
10860786Sps	struct ifile *prev;
10960786Sps{
11060786Sps	register struct ifile *p;
11160786Sps
11260786Sps	/*
11360786Sps	 * Allocate and initialize structure.
11460786Sps	 */
11560786Sps	p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
11660786Sps	p->h_filename = save(filename);
11760786Sps	p->h_scrpos.pos = NULL_POSITION;
11860786Sps	p->h_opened = 0;
11960786Sps	p->h_hold = 0;
12060786Sps	p->h_filestate = NULL;
12160786Sps	link_ifile(p, prev);
12260786Sps	return (p);
12360786Sps}
12460786Sps
12560786Sps/*
12660786Sps * Delete an existing ifile structure.
12760786Sps */
12860786Sps	public void
12960786Spsdel_ifile(h)
13060786Sps	IFILE h;
13160786Sps{
13260786Sps	register struct ifile *p;
13360786Sps
13460786Sps	if (h == NULL_IFILE)
13560786Sps		return;
13660786Sps	/*
13760786Sps	 * If the ifile we're deleting is the currently open ifile,
13860786Sps	 * move off it.
13960786Sps	 */
14060786Sps	unmark(h);
14160786Sps	if (h == curr_ifile)
14260786Sps		curr_ifile = getoff_ifile(curr_ifile);
14360786Sps	p = int_ifile(h);
14460786Sps	unlink_ifile(p);
14560786Sps	free(p->h_filename);
14660786Sps	free(p);
14760786Sps}
14860786Sps
14960786Sps/*
15060786Sps * Get the ifile after a given one in the list.
15160786Sps */
15260786Sps	public IFILE
15360786Spsnext_ifile(h)
15460786Sps	IFILE h;
15560786Sps{
15660786Sps	register struct ifile *p;
15760786Sps
15860786Sps	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
15960786Sps	if (p->h_next == &anchor)
16060786Sps		return (NULL_IFILE);
16160786Sps	return (ext_ifile(p->h_next));
16260786Sps}
16360786Sps
16460786Sps/*
16560786Sps * Get the ifile before a given one in the list.
16660786Sps */
16760786Sps	public IFILE
16860786Spsprev_ifile(h)
16960786Sps	IFILE h;
17060786Sps{
17160786Sps	register struct ifile *p;
17260786Sps
17360786Sps	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
17460786Sps	if (p->h_prev == &anchor)
17560786Sps		return (NULL_IFILE);
17660786Sps	return (ext_ifile(p->h_prev));
17760786Sps}
17860786Sps
17960786Sps/*
18060786Sps * Return a different ifile from the given one.
18160786Sps */
18260786Sps	public IFILE
18360786Spsgetoff_ifile(ifile)
18460786Sps	IFILE ifile;
18560786Sps{
18660786Sps	IFILE newifile;
18760786Sps
18860786Sps	if ((newifile = prev_ifile(ifile)) != NULL_IFILE)
18960786Sps		return (newifile);
19060786Sps	if ((newifile = next_ifile(ifile)) != NULL_IFILE)
19160786Sps		return (newifile);
19260786Sps	return (NULL_IFILE);
19360786Sps}
19460786Sps
19560786Sps/*
19660786Sps * Return the number of ifiles.
19760786Sps */
19860786Sps	public int
19960786Spsnifile()
20060786Sps{
20160786Sps	return (ifiles);
20260786Sps}
20360786Sps
20460786Sps/*
20560786Sps * Find an ifile structure, given a filename.
20660786Sps */
20760786Sps	static struct ifile *
20860786Spsfind_ifile(filename)
20960786Sps	char *filename;
21060786Sps{
21160786Sps	register struct ifile *p;
21260786Sps
21360786Sps	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
21460786Sps		if (strcmp(filename, p->h_filename) == 0)
21560786Sps			return (p);
21660786Sps	return (NULL);
21760786Sps}
21860786Sps
21960786Sps/*
22060786Sps * Get the ifile associated with a filename.
22160786Sps * If the filename has not been seen before,
22260786Sps * insert the new ifile after "prev" in the list.
22360786Sps */
22460786Sps	public IFILE
22560786Spsget_ifile(filename, prev)
22660786Sps	char *filename;
22760786Sps	IFILE prev;
22860786Sps{
22960786Sps	register struct ifile *p;
23060786Sps
23160786Sps	if ((p = find_ifile(filename)) == NULL)
23260786Sps		p = new_ifile(filename, int_ifile(prev));
23360786Sps	return (ext_ifile(p));
23460786Sps}
23560786Sps
23660786Sps/*
23760786Sps * Get the filename associated with a ifile.
23860786Sps */
23960786Sps	public char *
24060786Spsget_filename(ifile)
24160786Sps	IFILE ifile;
24260786Sps{
24360786Sps	if (ifile == NULL)
24460786Sps		return (NULL);
24560786Sps	return (int_ifile(ifile)->h_filename);
24660786Sps}
24760786Sps
24860786Sps/*
24960786Sps * Get the index of the file associated with a ifile.
25060786Sps */
25160786Sps	public int
25260786Spsget_index(ifile)
25360786Sps	IFILE ifile;
25460786Sps{
25560786Sps	return (int_ifile(ifile)->h_index);
25660786Sps}
25760786Sps
25860786Sps/*
25960786Sps * Save the file position to be associated with a given file.
26060786Sps */
26160786Sps	public void
26260786Spsstore_pos(ifile, scrpos)
26360786Sps	IFILE ifile;
26460786Sps	struct scrpos *scrpos;
26560786Sps{
26660786Sps	int_ifile(ifile)->h_scrpos = *scrpos;
26760786Sps}
26860786Sps
26960786Sps/*
27060786Sps * Recall the file position associated with a file.
27160786Sps * If no position has been associated with the file, return NULL_POSITION.
27260786Sps */
27360786Sps	public void
27460786Spsget_pos(ifile, scrpos)
27560786Sps	IFILE ifile;
27660786Sps	struct scrpos *scrpos;
27760786Sps{
27860786Sps	*scrpos = int_ifile(ifile)->h_scrpos;
27960786Sps}
28060786Sps
28160786Sps/*
28260786Sps * Mark the ifile as "opened".
28360786Sps */
28460786Sps	public void
28560786Spsset_open(ifile)
28660786Sps	IFILE ifile;
28760786Sps{
28860786Sps	int_ifile(ifile)->h_opened = 1;
28960786Sps}
29060786Sps
29160786Sps/*
29260786Sps * Return whether the ifile has been opened previously.
29360786Sps */
29460786Sps	public int
29560786Spsopened(ifile)
29660786Sps	IFILE ifile;
29760786Sps{
29860786Sps	return (int_ifile(ifile)->h_opened);
29960786Sps}
30060786Sps
30160786Sps	public void
30260786Spshold_ifile(ifile, incr)
30360786Sps	IFILE ifile;
30460786Sps	int incr;
30560786Sps{
30660786Sps	int_ifile(ifile)->h_hold += incr;
30760786Sps}
30860786Sps
30960786Sps	public int
31060786Spsheld_ifile(ifile)
31160786Sps	IFILE ifile;
31260786Sps{
31360786Sps	return (int_ifile(ifile)->h_hold);
31460786Sps}
31560786Sps
31660786Sps	public void *
31760786Spsget_filestate(ifile)
31860786Sps	IFILE ifile;
31960786Sps{
32060786Sps	return (int_ifile(ifile)->h_filestate);
32160786Sps}
32260786Sps
32360786Sps	public void
32460786Spsset_filestate(ifile, filestate)
32560786Sps	IFILE ifile;
32660786Sps	void *filestate;
32760786Sps{
32860786Sps	int_ifile(ifile)->h_filestate = filestate;
32960786Sps}
33060786Sps
33160786Sps#if 0
33260786Sps	public void
33360786Spsif_dump()
33460786Sps{
33560786Sps	register struct ifile *p;
33660786Sps
33760786Sps	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
33860786Sps	{
33960786Sps		printf("%x: %d. <%s> pos %d,%x\n",
34060786Sps			p, p->h_index, p->h_filename,
34160786Sps			p->h_scrpos.ln, p->h_scrpos.pos);
34260786Sps		ch_dump(p->h_filestate);
34360786Sps	}
34460786Sps}
34560786Sps#endif
346