1238730Sdelphij/*
2369759Sgit2svn * Copyright (C) 1984-2021  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
24369759Sgit2svnextern IFILE    curr_ifile;
2560786Sps
2660786Spsstruct ifile {
27330570Sdelphij	struct ifile *h_next;           /* Links for command line list */
2860786Sps	struct ifile *h_prev;
29330570Sdelphij	char *h_filename;               /* Name of the file */
30369759Sgit2svn	char *h_rfilename;              /* Canonical name of the file */
31330570Sdelphij	void *h_filestate;              /* File state (used in ch.c) */
32330570Sdelphij	int h_index;                    /* Index within command line list */
33330570Sdelphij	int h_hold;                     /* Hold count */
34330570Sdelphij	char h_opened;                  /* Has this ifile been opened? */
35330570Sdelphij	struct scrpos h_scrpos;         /* Saved position within the file */
36330570Sdelphij	void *h_altpipe;                /* Alt pipe */
37330570Sdelphij	char *h_altfilename;            /* Alt filename */
3860786Sps};
3960786Sps
4060786Sps/*
4160786Sps * Convert an IFILE (external representation)
4260786Sps * to a struct file (internal representation), and vice versa.
4360786Sps */
44369759Sgit2svn#define int_ifile(h)    ((struct ifile *)(h))
45369759Sgit2svn#define ext_ifile(h)    ((IFILE)(h))
4660786Sps
4760786Sps/*
4860786Sps * Anchor for linked list.
4960786Sps */
50369759Sgit2svnstatic struct ifile anchor = { &anchor, &anchor, NULL, NULL, NULL, 0, 0, '\0',
5160786Sps				{ NULL_POSITION, 0 } };
5260786Spsstatic int ifiles = 0;
5360786Sps
5460786Sps	static void
5560786Spsincr_index(p, incr)
56330570Sdelphij	struct ifile *p;
5760786Sps	int incr;
5860786Sps{
5960786Sps	for (;  p != &anchor;  p = p->h_next)
6060786Sps		p->h_index += incr;
6160786Sps}
6260786Sps
6360786Sps/*
6460786Sps * Link an ifile into the ifile list.
6560786Sps */
6660786Sps	static void
6760786Spslink_ifile(p, prev)
6860786Sps	struct ifile *p;
6960786Sps	struct ifile *prev;
7060786Sps{
7160786Sps	/*
7260786Sps	 * Link into list.
7360786Sps	 */
7460786Sps	if (prev == NULL)
7560786Sps		prev = &anchor;
7660786Sps	p->h_next = prev->h_next;
7760786Sps	p->h_prev = prev;
7860786Sps	prev->h_next->h_prev = p;
7960786Sps	prev->h_next = p;
8060786Sps	/*
8160786Sps	 * Calculate index for the new one,
8260786Sps	 * and adjust the indexes for subsequent ifiles in the list.
8360786Sps	 */
8460786Sps	p->h_index = prev->h_index + 1;
8560786Sps	incr_index(p->h_next, 1);
8660786Sps	ifiles++;
8760786Sps}
8860786Sps
8960786Sps/*
9060786Sps * Unlink an ifile from the ifile list.
9160786Sps */
9260786Sps	static void
9360786Spsunlink_ifile(p)
9460786Sps	struct ifile *p;
9560786Sps{
9660786Sps	p->h_next->h_prev = p->h_prev;
9760786Sps	p->h_prev->h_next = p->h_next;
9860786Sps	incr_index(p->h_next, -1);
9960786Sps	ifiles--;
10060786Sps}
10160786Sps
10260786Sps/*
10360786Sps * Allocate a new ifile structure and stick a filename in it.
10460786Sps * It should go after "prev" in the list
10560786Sps * (or at the beginning of the list if "prev" is NULL).
10660786Sps * Return a pointer to the new ifile structure.
10760786Sps */
10860786Sps	static struct ifile *
10960786Spsnew_ifile(filename, prev)
11060786Sps	char *filename;
11160786Sps	struct ifile *prev;
11260786Sps{
113330570Sdelphij	struct ifile *p;
11460786Sps
11560786Sps	/*
11660786Sps	 * Allocate and initialize structure.
11760786Sps	 */
11860786Sps	p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
11960786Sps	p->h_filename = save(filename);
120369759Sgit2svn	p->h_rfilename = lrealpath(filename);
12160786Sps	p->h_scrpos.pos = NULL_POSITION;
12260786Sps	p->h_opened = 0;
12360786Sps	p->h_hold = 0;
12460786Sps	p->h_filestate = NULL;
125369759Sgit2svn	p->h_altfilename = NULL;
126369759Sgit2svn	p->h_altpipe = NULL;
12760786Sps	link_ifile(p, prev);
128355504Sdelphij	/*
129355504Sdelphij	 * {{ It's dodgy to call mark.c functions from here;
130355504Sdelphij	 *    there is potentially dangerous recursion.
131355504Sdelphij	 *    Probably need to revisit this design. }}
132355504Sdelphij	 */
133355504Sdelphij	mark_check_ifile(ext_ifile(p));
13460786Sps	return (p);
13560786Sps}
13660786Sps
13760786Sps/*
13860786Sps * Delete an existing ifile structure.
13960786Sps */
14060786Sps	public void
14160786Spsdel_ifile(h)
14260786Sps	IFILE h;
14360786Sps{
144330570Sdelphij	struct ifile *p;
14560786Sps
14660786Sps	if (h == NULL_IFILE)
14760786Sps		return;
14860786Sps	/*
14960786Sps	 * If the ifile we're deleting is the currently open ifile,
15060786Sps	 * move off it.
15160786Sps	 */
15260786Sps	unmark(h);
15360786Sps	if (h == curr_ifile)
15460786Sps		curr_ifile = getoff_ifile(curr_ifile);
15560786Sps	p = int_ifile(h);
15660786Sps	unlink_ifile(p);
157369759Sgit2svn	free(p->h_rfilename);
15860786Sps	free(p->h_filename);
15960786Sps	free(p);
16060786Sps}
16160786Sps
16260786Sps/*
16360786Sps * Get the ifile after a given one in the list.
16460786Sps */
16560786Sps	public IFILE
16660786Spsnext_ifile(h)
16760786Sps	IFILE h;
16860786Sps{
169330570Sdelphij	struct ifile *p;
17060786Sps
17160786Sps	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
17260786Sps	if (p->h_next == &anchor)
17360786Sps		return (NULL_IFILE);
17460786Sps	return (ext_ifile(p->h_next));
17560786Sps}
17660786Sps
17760786Sps/*
17860786Sps * Get the ifile before a given one in the list.
17960786Sps */
18060786Sps	public IFILE
18160786Spsprev_ifile(h)
18260786Sps	IFILE h;
18360786Sps{
184330570Sdelphij	struct ifile *p;
18560786Sps
18660786Sps	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
18760786Sps	if (p->h_prev == &anchor)
18860786Sps		return (NULL_IFILE);
18960786Sps	return (ext_ifile(p->h_prev));
19060786Sps}
19160786Sps
19260786Sps/*
19360786Sps * Return a different ifile from the given one.
19460786Sps */
19560786Sps	public IFILE
19660786Spsgetoff_ifile(ifile)
19760786Sps	IFILE ifile;
19860786Sps{
19960786Sps	IFILE newifile;
20060786Sps
20160786Sps	if ((newifile = prev_ifile(ifile)) != NULL_IFILE)
20260786Sps		return (newifile);
20360786Sps	if ((newifile = next_ifile(ifile)) != NULL_IFILE)
20460786Sps		return (newifile);
20560786Sps	return (NULL_IFILE);
20660786Sps}
20760786Sps
20860786Sps/*
20960786Sps * Return the number of ifiles.
21060786Sps */
21160786Sps	public int
212355504Sdelphijnifile(VOID_PARAM)
21360786Sps{
21460786Sps	return (ifiles);
21560786Sps}
21660786Sps
21760786Sps/*
21860786Sps * Find an ifile structure, given a filename.
21960786Sps */
22060786Sps	static struct ifile *
22160786Spsfind_ifile(filename)
22260786Sps	char *filename;
22360786Sps{
224330570Sdelphij	struct ifile *p;
225355504Sdelphij	char *rfilename = lrealpath(filename);
22660786Sps
22760786Sps	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
228355504Sdelphij	{
229369759Sgit2svn		if (strcmp(rfilename, p->h_rfilename) == 0)
230355504Sdelphij		{
231355504Sdelphij			/*
232355504Sdelphij			 * If given name is shorter than the name we were
233355504Sdelphij			 * previously using for this file, adopt shorter name.
234355504Sdelphij			 */
235355504Sdelphij			if (strlen(filename) < strlen(p->h_filename))
236369759Sgit2svn			{
237369759Sgit2svn				free(p->h_filename);
238369759Sgit2svn				p->h_filename = save(filename);
239369759Sgit2svn			}
240355504Sdelphij			break;
241355504Sdelphij		}
242355504Sdelphij	}
243355504Sdelphij	free(rfilename);
244355504Sdelphij	if (p == &anchor)
245355504Sdelphij		p = NULL;
246355504Sdelphij	return (p);
24760786Sps}
24860786Sps
24960786Sps/*
25060786Sps * Get the ifile associated with a filename.
25160786Sps * If the filename has not been seen before,
25260786Sps * insert the new ifile after "prev" in the list.
25360786Sps */
25460786Sps	public IFILE
25560786Spsget_ifile(filename, prev)
25660786Sps	char *filename;
25760786Sps	IFILE prev;
25860786Sps{
259330570Sdelphij	struct ifile *p;
26060786Sps
26160786Sps	if ((p = find_ifile(filename)) == NULL)
26260786Sps		p = new_ifile(filename, int_ifile(prev));
26360786Sps	return (ext_ifile(p));
26460786Sps}
26560786Sps
26660786Sps/*
267369759Sgit2svn * Get the display filename associated with a ifile.
26860786Sps */
26960786Sps	public char *
27060786Spsget_filename(ifile)
27160786Sps	IFILE ifile;
27260786Sps{
27360786Sps	if (ifile == NULL)
27460786Sps		return (NULL);
27560786Sps	return (int_ifile(ifile)->h_filename);
27660786Sps}
27760786Sps
27860786Sps/*
279369759Sgit2svn * Get the canonical filename associated with a ifile.
280369759Sgit2svn */
281369759Sgit2svn	public char *
282369759Sgit2svnget_real_filename(ifile)
283369759Sgit2svn	IFILE ifile;
284369759Sgit2svn{
285369759Sgit2svn	if (ifile == NULL)
286369759Sgit2svn		return (NULL);
287369759Sgit2svn	return (int_ifile(ifile)->h_rfilename);
288369759Sgit2svn}
289369759Sgit2svn
290369759Sgit2svn/*
29160786Sps * Get the index of the file associated with a ifile.
29260786Sps */
29360786Sps	public int
29460786Spsget_index(ifile)
29560786Sps	IFILE ifile;
29660786Sps{
29760786Sps	return (int_ifile(ifile)->h_index);
29860786Sps}
29960786Sps
30060786Sps/*
30160786Sps * Save the file position to be associated with a given file.
30260786Sps */
30360786Sps	public void
30460786Spsstore_pos(ifile, scrpos)
30560786Sps	IFILE ifile;
30660786Sps	struct scrpos *scrpos;
30760786Sps{
30860786Sps	int_ifile(ifile)->h_scrpos = *scrpos;
30960786Sps}
31060786Sps
31160786Sps/*
31260786Sps * Recall the file position associated with a file.
31360786Sps * If no position has been associated with the file, return NULL_POSITION.
31460786Sps */
31560786Sps	public void
31660786Spsget_pos(ifile, scrpos)
31760786Sps	IFILE ifile;
31860786Sps	struct scrpos *scrpos;
31960786Sps{
32060786Sps	*scrpos = int_ifile(ifile)->h_scrpos;
32160786Sps}
32260786Sps
32360786Sps/*
32460786Sps * Mark the ifile as "opened".
32560786Sps */
32660786Sps	public void
32760786Spsset_open(ifile)
32860786Sps	IFILE ifile;
32960786Sps{
33060786Sps	int_ifile(ifile)->h_opened = 1;
33160786Sps}
33260786Sps
33360786Sps/*
33460786Sps * Return whether the ifile has been opened previously.
33560786Sps */
33660786Sps	public int
33760786Spsopened(ifile)
33860786Sps	IFILE ifile;
33960786Sps{
34060786Sps	return (int_ifile(ifile)->h_opened);
34160786Sps}
34260786Sps
34360786Sps	public void
34460786Spshold_ifile(ifile, incr)
34560786Sps	IFILE ifile;
34660786Sps	int incr;
34760786Sps{
34860786Sps	int_ifile(ifile)->h_hold += incr;
34960786Sps}
35060786Sps
35160786Sps	public int
35260786Spsheld_ifile(ifile)
35360786Sps	IFILE ifile;
35460786Sps{
35560786Sps	return (int_ifile(ifile)->h_hold);
35660786Sps}
35760786Sps
35860786Sps	public void *
35960786Spsget_filestate(ifile)
36060786Sps	IFILE ifile;
36160786Sps{
36260786Sps	return (int_ifile(ifile)->h_filestate);
36360786Sps}
36460786Sps
36560786Sps	public void
36660786Spsset_filestate(ifile, filestate)
36760786Sps	IFILE ifile;
36860786Sps	void *filestate;
36960786Sps{
37060786Sps	int_ifile(ifile)->h_filestate = filestate;
37160786Sps}
37260786Sps
373330570Sdelphij	public void
374330570Sdelphijset_altpipe(ifile, p)
375330570Sdelphij	IFILE ifile;
376330570Sdelphij	void *p;
377330570Sdelphij{
378330570Sdelphij	int_ifile(ifile)->h_altpipe = p;
379330570Sdelphij}
380330570Sdelphij
381330570Sdelphij	public void *
382330570Sdelphijget_altpipe(ifile)
383330570Sdelphij	IFILE ifile;
384330570Sdelphij{
385330570Sdelphij	return (int_ifile(ifile)->h_altpipe);
386330570Sdelphij}
387330570Sdelphij
388330570Sdelphij	public void
389330570Sdelphijset_altfilename(ifile, altfilename)
390330570Sdelphij	IFILE ifile;
391330570Sdelphij	char *altfilename;
392330570Sdelphij{
393330570Sdelphij	struct ifile *p = int_ifile(ifile);
394369759Sgit2svn	if (p->h_altfilename != NULL && p->h_altfilename != altfilename)
395330570Sdelphij		free(p->h_altfilename);
396330570Sdelphij	p->h_altfilename = altfilename;
397330570Sdelphij}
398330570Sdelphij
399330570Sdelphij	public char *
400330570Sdelphijget_altfilename(ifile)
401330570Sdelphij	IFILE ifile;
402330570Sdelphij{
403330570Sdelphij	return (int_ifile(ifile)->h_altfilename);
404330570Sdelphij}
405330570Sdelphij
40660786Sps#if 0
40760786Sps	public void
408355504Sdelphijif_dump(VOID_PARAM)
40960786Sps{
410330570Sdelphij	struct ifile *p;
41160786Sps
41260786Sps	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
41360786Sps	{
41460786Sps		printf("%x: %d. <%s> pos %d,%x\n",
41560786Sps			p, p->h_index, p->h_filename,
41660786Sps			p->h_scrpos.ln, p->h_scrpos.pos);
41760786Sps		ch_dump(p->h_filestate);
41860786Sps	}
41960786Sps}
42060786Sps#endif
421