ifile.c revision 60786
1168404Spjd/*
2168404Spjd * Copyright (C) 1984-2000  Mark Nudelman
3168404Spjd *
4168404Spjd * You may distribute under the terms of either the GNU General Public
5168404Spjd * License or the Less License, as specified in the README file.
6168404Spjd *
7168404Spjd * For more information about less, or for information on how to
8168404Spjd * contact the author, see the README file.
9168404Spjd */
10168404Spjd
11168404Spjd
12168404Spjd/*
13168404Spjd * An IFILE represents an input file.
14168404Spjd *
15168404Spjd * It is actually a pointer to an ifile structure,
16168404Spjd * but is opaque outside this module.
17168404Spjd * Ifile structures are kept in a linked list in the order they
18168404Spjd * appear on the command line.
19168404Spjd * Any new file which does not already appear in the list is
20168404Spjd * inserted after the current file.
21168404Spjd */
22205198Sdelphij
23168404Spjd#include "less.h"
24168404Spjd
25168404Spjdextern IFILE	curr_ifile;
26168404Spjd
27168404Spjdstruct ifile {
28168404Spjd	struct ifile *h_next;		/* Links for command line list */
29168404Spjd	struct ifile *h_prev;
30168404Spjd	char *h_filename;		/* Name of the file */
31168404Spjd	void *h_filestate;		/* File state (used in ch.c) */
32168404Spjd	int h_index;			/* Index within command line list */
33168404Spjd	int h_hold;			/* Hold count */
34168404Spjd	char h_opened;			/* Has this ifile been opened? */
35168404Spjd	struct scrpos h_scrpos;		/* Saved position within the file */
36168404Spjd};
37168404Spjd
38168404Spjd/*
39168404Spjd * Convert an IFILE (external representation)
40168404Spjd * to a struct file (internal representation), and vice versa.
41168404Spjd */
42168404Spjd#define int_ifile(h)	((struct ifile *)(h))
43168404Spjd#define ext_ifile(h)	((IFILE)(h))
44168404Spjd
45168404Spjd/*
46168404Spjd * Anchor for linked list.
47168404Spjd */
48168404Spjdstatic struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0',
49168404Spjd				{ NULL_POSITION, 0 } };
50168404Spjdstatic int ifiles = 0;
51168404Spjd
52168404Spjd	static void
53168404Spjdincr_index(p, incr)
54168404Spjd	register struct ifile *p;
55168404Spjd	int incr;
56205199Sdelphij{
57205199Sdelphij	for (;  p != &anchor;  p = p->h_next)
58205199Sdelphij		p->h_index += incr;
59205199Sdelphij}
60205199Sdelphij
61205199Sdelphij/*
62205199Sdelphij * Link an ifile into the ifile list.
63205199Sdelphij */
64168404Spjd	static void
65168404Spjdlink_ifile(p, prev)
66168404Spjd	struct ifile *p;
67168404Spjd	struct ifile *prev;
68168404Spjd{
69185029Spjd	/*
70185029Spjd	 * Link into list.
71185029Spjd	 */
72185029Spjd	if (prev == NULL)
73185029Spjd		prev = &anchor;
74185029Spjd	p->h_next = prev->h_next;
75185029Spjd	p->h_prev = prev;
76185029Spjd	prev->h_next->h_prev = p;
77185029Spjd	prev->h_next = p;
78185029Spjd	/*
79185029Spjd	 * Calculate index for the new one,
80185029Spjd	 * and adjust the indexes for subsequent ifiles in the list.
81185029Spjd	 */
82185029Spjd	p->h_index = prev->h_index + 1;
83185029Spjd	incr_index(p->h_next, 1);
84185029Spjd	ifiles++;
85185029Spjd}
86168404Spjd
87168404Spjd/*
88185029Spjd * Unlink an ifile from the ifile list.
89168404Spjd */
90168404Spjd	static void
91168404Spjdunlink_ifile(p)
92168404Spjd	struct ifile *p;
93185029Spjd{
94168404Spjd	p->h_next->h_prev = p->h_prev;
95185029Spjd	p->h_prev->h_next = p->h_next;
96185029Spjd	incr_index(p->h_next, -1);
97168404Spjd	ifiles--;
98168404Spjd}
99168404Spjd
100168404Spjd/*
101168404Spjd * Allocate a new ifile structure and stick a filename in it.
102168404Spjd * It should go after "prev" in the list
103168404Spjd * (or at the beginning of the list if "prev" is NULL).
104205198Sdelphij * Return a pointer to the new ifile structure.
105205198Sdelphij */
106205198Sdelphij	static struct ifile *
107205198Sdelphijnew_ifile(filename, prev)
108205198Sdelphij	char *filename;
109205198Sdelphij	struct ifile *prev;
110205198Sdelphij{
111205198Sdelphij	register struct ifile *p;
112205198Sdelphij
113205198Sdelphij	/*
114205198Sdelphij	 * Allocate and initialize structure.
115168404Spjd	 */
116168404Spjd	p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
117168404Spjd	p->h_filename = save(filename);
118168404Spjd	p->h_scrpos.pos = NULL_POSITION;
119168404Spjd	p->h_opened = 0;
120168404Spjd	p->h_hold = 0;
121168404Spjd	p->h_filestate = NULL;
122168404Spjd	link_ifile(p, prev);
123168404Spjd	return (p);
124168404Spjd}
125168404Spjd
126205199Sdelphij/*
127205199Sdelphij * Delete an existing ifile structure.
128205199Sdelphij */
129205199Sdelphij	public void
130185029Spjddel_ifile(h)
131185029Spjd	IFILE h;
132185029Spjd{
133185029Spjd	register struct ifile *p;
134205199Sdelphij
135185029Spjd	if (h == NULL_IFILE)
136168404Spjd		return;
137168404Spjd	/*
138168404Spjd	 * If the ifile we're deleting is the currently open ifile,
139168404Spjd	 * move off it.
140168404Spjd	 */
141168404Spjd	unmark(h);
142168404Spjd	if (h == curr_ifile)
143168404Spjd		curr_ifile = getoff_ifile(curr_ifile);
144168404Spjd	p = int_ifile(h);
145168404Spjd	unlink_ifile(p);
146168404Spjd	free(p->h_filename);
147168404Spjd	free(p);
148168404Spjd}
149168404Spjd
150185029Spjd/*
151168404Spjd * Get the ifile after a given one in the list.
152168404Spjd */
153168404Spjd	public IFILE
154168404Spjdnext_ifile(h)
155168404Spjd	IFILE h;
156168404Spjd{
157168404Spjd	register struct ifile *p;
158185029Spjd
159168404Spjd	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
160168404Spjd	if (p->h_next == &anchor)
161168404Spjd		return (NULL_IFILE);
162168404Spjd	return (ext_ifile(p->h_next));
163168404Spjd}
164168404Spjd
165168404Spjd/*
166168404Spjd * Get the ifile before a given one in the list.
167168404Spjd */
168168404Spjd	public IFILE
169168404Spjdprev_ifile(h)
170168404Spjd	IFILE h;
171168404Spjd{
172168404Spjd	register struct ifile *p;
173168404Spjd
174168404Spjd	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
175168404Spjd	if (p->h_prev == &anchor)
176168404Spjd		return (NULL_IFILE);
177168404Spjd	return (ext_ifile(p->h_prev));
178168404Spjd}
179168404Spjd
180168404Spjd/*
181168404Spjd * Return a different ifile from the given one.
182168404Spjd */
183168404Spjd	public IFILE
184168404Spjdgetoff_ifile(ifile)
185168404Spjd	IFILE ifile;
186168404Spjd{
187168404Spjd	IFILE newifile;
188168404Spjd
189168404Spjd	if ((newifile = prev_ifile(ifile)) != NULL_IFILE)
190168404Spjd		return (newifile);
191168404Spjd	if ((newifile = next_ifile(ifile)) != NULL_IFILE)
192168404Spjd		return (newifile);
193168404Spjd	return (NULL_IFILE);
194168404Spjd}
195168404Spjd
196168404Spjd/*
197168404Spjd * Return the number of ifiles.
198168404Spjd */
199168404Spjd	public int
200168404Spjdnifile()
201168404Spjd{
202168404Spjd	return (ifiles);
203168404Spjd}
204168404Spjd
205168404Spjd/*
206168404Spjd * Find an ifile structure, given a filename.
207168404Spjd */
208168404Spjd	static struct ifile *
209168404Spjdfind_ifile(filename)
210168404Spjd	char *filename;
211168404Spjd{
212168404Spjd	register struct ifile *p;
213168404Spjd
214168404Spjd	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
215168404Spjd		if (strcmp(filename, p->h_filename) == 0)
216168404Spjd			return (p);
217168404Spjd	return (NULL);
218168404Spjd}
219168404Spjd
220168404Spjd/*
221168404Spjd * Get the ifile associated with a filename.
222168404Spjd * If the filename has not been seen before,
223168404Spjd * insert the new ifile after "prev" in the list.
224168404Spjd */
225168404Spjd	public IFILE
226168404Spjdget_ifile(filename, prev)
227168404Spjd	char *filename;
228168404Spjd	IFILE prev;
229168404Spjd{
230168404Spjd	register struct ifile *p;
231168404Spjd
232168404Spjd	if ((p = find_ifile(filename)) == NULL)
233168404Spjd		p = new_ifile(filename, int_ifile(prev));
234168404Spjd	return (ext_ifile(p));
235168404Spjd}
236168404Spjd
237168404Spjd/*
238168404Spjd * Get the filename associated with a ifile.
239168404Spjd */
240168404Spjd	public char *
241168404Spjdget_filename(ifile)
242168404Spjd	IFILE ifile;
243168404Spjd{
244168404Spjd	if (ifile == NULL)
245168404Spjd		return (NULL);
246168404Spjd	return (int_ifile(ifile)->h_filename);
247168404Spjd}
248168404Spjd
249168404Spjd/*
250168404Spjd * Get the index of the file associated with a ifile.
251168404Spjd */
252168404Spjd	public int
253168404Spjdget_index(ifile)
254168404Spjd	IFILE ifile;
255168404Spjd{
256168404Spjd	return (int_ifile(ifile)->h_index);
257168404Spjd}
258168404Spjd
259168404Spjd/*
260168404Spjd * Save the file position to be associated with a given file.
261168404Spjd */
262168404Spjd	public void
263168404Spjdstore_pos(ifile, scrpos)
264168404Spjd	IFILE ifile;
265168404Spjd	struct scrpos *scrpos;
266168404Spjd{
267168404Spjd	int_ifile(ifile)->h_scrpos = *scrpos;
268168404Spjd}
269168404Spjd
270168404Spjd/*
271168404Spjd * Recall the file position associated with a file.
272168404Spjd * If no position has been associated with the file, return NULL_POSITION.
273168404Spjd */
274168404Spjd	public void
275185029Spjdget_pos(ifile, scrpos)
276168404Spjd	IFILE ifile;
277168404Spjd	struct scrpos *scrpos;
278168404Spjd{
279168404Spjd	*scrpos = int_ifile(ifile)->h_scrpos;
280168404Spjd}
281168404Spjd
282168404Spjd/*
283168404Spjd * Mark the ifile as "opened".
284168404Spjd */
285168404Spjd	public void
286168404Spjdset_open(ifile)
287168404Spjd	IFILE ifile;
288168404Spjd{
289185029Spjd	int_ifile(ifile)->h_opened = 1;
290168404Spjd}
291168404Spjd
292185029Spjd/*
293168404Spjd * Return whether the ifile has been opened previously.
294168404Spjd */
295168404Spjd	public int
296168404Spjdopened(ifile)
297168404Spjd	IFILE ifile;
298168404Spjd{
299168404Spjd	return (int_ifile(ifile)->h_opened);
300168404Spjd}
301168404Spjd
302168404Spjd	public void
303168404Spjdhold_ifile(ifile, incr)
304168404Spjd	IFILE ifile;
305168404Spjd	int incr;
306168404Spjd{
307168404Spjd	int_ifile(ifile)->h_hold += incr;
308168404Spjd}
309168404Spjd
310168404Spjd	public int
311168404Spjdheld_ifile(ifile)
312168404Spjd	IFILE ifile;
313168404Spjd{
314168404Spjd	return (int_ifile(ifile)->h_hold);
315168404Spjd}
316168404Spjd
317168404Spjd	public void *
318168404Spjdget_filestate(ifile)
319168404Spjd	IFILE ifile;
320168404Spjd{
321168404Spjd	return (int_ifile(ifile)->h_filestate);
322168404Spjd}
323168404Spjd
324168404Spjd	public void
325185029Spjdset_filestate(ifile, filestate)
326168404Spjd	IFILE ifile;
327168404Spjd	void *filestate;
328168404Spjd{
329168404Spjd	int_ifile(ifile)->h_filestate = filestate;
330168404Spjd}
331168404Spjd
332168404Spjd#if 0
333168404Spjd	public void
334168404Spjdif_dump()
335168404Spjd{
336168404Spjd	register struct ifile *p;
337168404Spjd
338168404Spjd	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
339168404Spjd	{
340168404Spjd		printf("%x: %d. <%s> pos %d,%x\n",
341185029Spjd			p, p->h_index, p->h_filename,
342205199Sdelphij			p->h_scrpos.ln, p->h_scrpos.pos);
343185029Spjd		ch_dump(p->h_filestate);
344168404Spjd	}
345205198Sdelphij}
346168404Spjd#endif
347168404Spjd