ifile.c revision 294286
155714Skris/*
255714Skris * Copyright (C) 1984-2015  Mark Nudelman
355714Skris *
455714Skris * You may distribute under the terms of either the GNU General Public
555714Skris * License or the Less License, as specified in the README file.
655714Skris *
755714Skris * For more information, see the README file.
855714Skris */
955714Skris
1055714Skris
1155714Skris/*
1255714Skris * An IFILE represents an input file.
1355714Skris *
1455714Skris * It is actually a pointer to an ifile structure,
1555714Skris * but is opaque outside this module.
1655714Skris * Ifile structures are kept in a linked list in the order they
1755714Skris * appear on the command line.
1855714Skris * Any new file which does not already appear in the list is
1955714Skris * inserted after the current file.
2055714Skris */
2155714Skris
2255714Skris#include "less.h"
2355714Skris
2455714Skrisextern IFILE	curr_ifile;
2555714Skris
2655714Skrisstruct ifile {
2755714Skris	struct ifile *h_next;		/* Links for command line list */
2855714Skris	struct ifile *h_prev;
2955714Skris	char *h_filename;		/* Name of the file */
3055714Skris	void *h_filestate;		/* File state (used in ch.c) */
3155714Skris	int h_index;			/* Index within command line list */
3255714Skris	int h_hold;			/* Hold count */
3355714Skris	char h_opened;			/* Has this ifile been opened? */
3455714Skris	struct scrpos h_scrpos;		/* Saved position within the file */
3555714Skris};
3655714Skris
3755714Skris/*
3855714Skris * Convert an IFILE (external representation)
3955714Skris * to a struct file (internal representation), and vice versa.
4055714Skris */
4155714Skris#define int_ifile(h)	((struct ifile *)(h))
4255714Skris#define ext_ifile(h)	((IFILE)(h))
4355714Skris
4455714Skris/*
4555714Skris * Anchor for linked list.
4655714Skris */
4755714Skrisstatic struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0',
4855714Skris				{ NULL_POSITION, 0 } };
4955714Skrisstatic int ifiles = 0;
5055714Skris
5155714Skris	static void
5255714Skrisincr_index(p, incr)
5355714Skris	register struct ifile *p;
5455714Skris	int incr;
5555714Skris{
5655714Skris	for (;  p != &anchor;  p = p->h_next)
5755714Skris		p->h_index += incr;
5855714Skris}
5955714Skris
6055714Skris/*
6155714Skris * Link an ifile into the ifile list.
6268654Skris */
6368654Skris	static void
6468654Skrislink_ifile(p, prev)
6568654Skris	struct ifile *p;
6668654Skris	struct ifile *prev;
6768654Skris{
6855714Skris	/*
6955714Skris	 * Link into list.
70110007Smarkm	 */
71110007Smarkm	if (prev == NULL)
72110007Smarkm		prev = &anchor;
73110007Smarkm	p->h_next = prev->h_next;
74110007Smarkm	p->h_prev = prev;
7568654Skris	prev->h_next->h_prev = p;
7668654Skris	prev->h_next = p;
7755714Skris	/*
78110007Smarkm	 * Calculate index for the new one,
7955714Skris	 * and adjust the indexes for subsequent ifiles in the list.
8055714Skris	 */
8155714Skris	p->h_index = prev->h_index + 1;
8255714Skris	incr_index(p->h_next, 1);
8355714Skris	ifiles++;
84110007Smarkm}
85160817Ssimon
86238405Sjkim/*
87110007Smarkm * Unlink an ifile from the ifile list.
88110007Smarkm */
8955714Skris	static void
9055714Skrisunlink_ifile(p)
9155714Skris	struct ifile *p;
9255714Skris{
9355714Skris	p->h_next->h_prev = p->h_prev;
9455714Skris	p->h_prev->h_next = p->h_next;
9555714Skris	incr_index(p->h_next, -1);
9655714Skris	ifiles--;
9755714Skris}
9855714Skris
99160817Ssimon/*
10055714Skris * Allocate a new ifile structure and stick a filename in it.
10155714Skris * It should go after "prev" in the list
10255714Skris * (or at the beginning of the list if "prev" is NULL).
10355714Skris * Return a pointer to the new ifile structure.
10455714Skris */
105160817Ssimon	static struct ifile *
10655714Skrisnew_ifile(filename, prev)
10755714Skris	char *filename;
10855714Skris	struct ifile *prev;
10955714Skris{
11055714Skris	register struct ifile *p;
11155714Skris
11255714Skris	/*
11355714Skris	 * Allocate and initialize structure.
11455714Skris	 */
11555714Skris	p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
11655714Skris	p->h_filename = save(filename);
117160817Ssimon	p->h_scrpos.pos = NULL_POSITION;
118238405Sjkim	p->h_opened = 0;
119238405Sjkim	p->h_hold = 0;
12055714Skris	p->h_filestate = NULL;
12168654Skris	link_ifile(p, prev);
12268654Skris	return (p);
12368654Skris}
12468654Skris
12555714Skris/*
12655714Skris * Delete an existing ifile structure.
12759194Skris */
128110007Smarkm	public void
12955714Skrisdel_ifile(h)
13055714Skris	IFILE h;
13155714Skris{
13255714Skris	register struct ifile *p;
133238405Sjkim
134238405Sjkim	if (h == NULL_IFILE)
13555714Skris		return;
13655714Skris	/*
137110007Smarkm	 * If the ifile we're deleting is the currently open ifile,
13855714Skris	 * move off it.
13955714Skris	 */
140110007Smarkm	unmark(h);
14155714Skris	if (h == curr_ifile)
14255714Skris		curr_ifile = getoff_ifile(curr_ifile);
143110007Smarkm	p = int_ifile(h);
14455714Skris	unlink_ifile(p);
14555714Skris	free(p->h_filename);
146160817Ssimon	free(p);
147160817Ssimon}
148160817Ssimon
14955714Skris/*
15055714Skris * Get the ifile after a given one in the list.
15168654Skris */
152110007Smarkm	public IFILE
15355714Skrisnext_ifile(h)
15455714Skris	IFILE h;
15555714Skris{
15655714Skris	register struct ifile *p;
15755714Skris
15855714Skris	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
15955714Skris	if (p->h_next == &anchor)
160110007Smarkm		return (NULL_IFILE);
16155714Skris	return (ext_ifile(p->h_next));
16255714Skris}
16355714Skris
16455714Skris/*
165110007Smarkm * Get the ifile before a given one in the list.
166110007Smarkm */
167160817Ssimon	public IFILE
168110007Smarkmprev_ifile(h)
169110007Smarkm	IFILE h;
170110007Smarkm{
17155714Skris	register struct ifile *p;
172110007Smarkm
173160817Ssimon	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
174160817Ssimon	if (p->h_prev == &anchor)
175160817Ssimon		return (NULL_IFILE);
176160817Ssimon	return (ext_ifile(p->h_prev));
177160817Ssimon}
17855714Skris
17955714Skris/*
180110007Smarkm * Return a different ifile from the given one.
181238405Sjkim */
182238405Sjkim	public IFILE
183110007Smarkmgetoff_ifile(ifile)
18455714Skris	IFILE ifile;
185160817Ssimon{
186160817Ssimon	IFILE newifile;
187160817Ssimon
188160817Ssimon	if ((newifile = prev_ifile(ifile)) != NULL_IFILE)
189160817Ssimon		return (newifile);
190160817Ssimon	if ((newifile = next_ifile(ifile)) != NULL_IFILE)
191160817Ssimon		return (newifile);
192110007Smarkm	return (NULL_IFILE);
193110007Smarkm}
19455714Skris
195238405Sjkim/*
196238405Sjkim * Return the number of ifiles.
197238405Sjkim */
198238405Sjkim	public int
199238405Sjkimnifile()
200238405Sjkim{
201238405Sjkim	return (ifiles);
202238405Sjkim}
203238405Sjkim
204238405Sjkim/*
205238405Sjkim * Find an ifile structure, given a filename.
206238405Sjkim */
207238405Sjkim	static struct ifile *
208238405Sjkimfind_ifile(filename)
209238405Sjkim	char *filename;
210238405Sjkim{
211238405Sjkim	register struct ifile *p;
212238405Sjkim
213238405Sjkim	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
214238405Sjkim		if (strcmp(filename, p->h_filename) == 0)
215238405Sjkim			return (p);
216238405Sjkim	return (NULL);
217238405Sjkim}
218238405Sjkim
219238405Sjkim/*
220194206Ssimon * Get the ifile associated with a filename.
221194206Ssimon * If the filename has not been seen before,
222238405Sjkim * insert the new ifile after "prev" in the list.
223194206Ssimon */
224238405Sjkim	public IFILE
225238405Sjkimget_ifile(filename, prev)
226238405Sjkim	char *filename;
227238405Sjkim	IFILE prev;
228238405Sjkim{
229238405Sjkim	register struct ifile *p;
230238405Sjkim
23155714Skris	if ((p = find_ifile(filename)) == NULL)
23255714Skris		p = new_ifile(filename, int_ifile(prev));
233110007Smarkm	return (ext_ifile(p));
234160817Ssimon}
235160817Ssimon
23655714Skris/*
23755714Skris * Get the filename associated with a ifile.
23855714Skris */
23955714Skris	public char *
24055714Skrisget_filename(ifile)
24155714Skris	IFILE ifile;
242160817Ssimon{
243160817Ssimon	if (ifile == NULL)
244160817Ssimon		return (NULL);
245160817Ssimon	return (int_ifile(ifile)->h_filename);
246160817Ssimon}
247160817Ssimon
248160817Ssimon/*
249160817Ssimon * Get the index of the file associated with a ifile.
250110007Smarkm */
251160817Ssimon	public int
252160817Ssimonget_index(ifile)
25355714Skris	IFILE ifile;
25455714Skris{
255160817Ssimon	return (int_ifile(ifile)->h_index);
256160817Ssimon}
25755714Skris
25855714Skris/*
25955714Skris * Save the file position to be associated with a given file.
26055714Skris */
26155714Skris	public void
26255714Skrisstore_pos(ifile, scrpos)
26355714Skris	IFILE ifile;
26455714Skris	struct scrpos *scrpos;
265110007Smarkm{
26655714Skris	int_ifile(ifile)->h_scrpos = *scrpos;
26755714Skris}
268110007Smarkm
269110007Smarkm/*
270110007Smarkm * Recall the file position associated with a file.
271238405Sjkim * If no position has been associated with the file, return NULL_POSITION.
272238405Sjkim */
273238405Sjkim	public void
274238405Sjkimget_pos(ifile, scrpos)
275110007Smarkm	IFILE ifile;
27655714Skris	struct scrpos *scrpos;
277110007Smarkm{
27868654Skris	*scrpos = int_ifile(ifile)->h_scrpos;
279110007Smarkm}
280110007Smarkm
281110007Smarkm/*
282110007Smarkm * Mark the ifile as "opened".
283127134Snectar */
284127134Snectar	public void
285238405Sjkimset_open(ifile)
286238405Sjkim	IFILE ifile;
287238405Sjkim{
288238405Sjkim	int_ifile(ifile)->h_opened = 1;
289194206Ssimon}
290194206Ssimon
291110007Smarkm/*
292238405Sjkim * Return whether the ifile has been opened previously.
293238405Sjkim */
294238405Sjkim	public int
295238405Sjkimopened(ifile)
296194206Ssimon	IFILE ifile;
297194206Ssimon{
298194206Ssimon	return (int_ifile(ifile)->h_opened);
299194206Ssimon}
300194206Ssimon
301238405Sjkim	public void
302238405Sjkimhold_ifile(ifile, incr)
30368654Skris	IFILE ifile;
30455714Skris	int incr;
30555714Skris{
30655714Skris	int_ifile(ifile)->h_hold += incr;
30768654Skris}
30855714Skris
30968654Skris	public int
31068654Skrisheld_ifile(ifile)
31168654Skris	IFILE ifile;
31268654Skris{
313238405Sjkim	return (int_ifile(ifile)->h_hold);
31468654Skris}
315110007Smarkm
31668654Skris	public void *
31768654Skrisget_filestate(ifile)
31868654Skris	IFILE ifile;
31968654Skris{
320110007Smarkm	return (int_ifile(ifile)->h_filestate);
32155714Skris}
32268654Skris
32368654Skris	public void
32468654Skrisset_filestate(ifile, filestate)
32568654Skris	IFILE ifile;
32668654Skris	void *filestate;
32768654Skris{
32868654Skris	int_ifile(ifile)->h_filestate = filestate;
32968654Skris}
33068654Skris
331238405Sjkim#if 0
332238405Sjkim	public void
333238405Sjkimif_dump()
334238405Sjkim{
335238405Sjkim	register struct ifile *p;
33668654Skris
33768654Skris	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
33868654Skris	{
33968654Skris		printf("%x: %d. <%s> pos %d,%x\n",
34068654Skris			p, p->h_index, p->h_filename,
34168654Skris			p->h_scrpos.ln, p->h_scrpos.pos);
34268654Skris		ch_dump(p->h_filestate);
34368654Skris	}
34468654Skris}
34568654Skris#endif
346110007Smarkm