ifile.c revision 294286
1254721Semaste/*
2254721Semaste * Copyright (C) 1984-2015  Mark Nudelman
3353358Sdim *
4353358Sdim * You may distribute under the terms of either the GNU General Public
5353358Sdim * License or the Less License, as specified in the README file.
6254721Semaste *
7254721Semaste * For more information, see the README file.
8254721Semaste */
9254721Semaste
10254721Semaste
11254721Semaste/*
12254721Semaste * An IFILE represents an input file.
13254721Semaste *
14254721Semaste * It is actually a pointer to an ifile structure,
15254721Semaste * but is opaque outside this module.
16254721Semaste * Ifile structures are kept in a linked list in the order they
17314564Sdim * appear on the command line.
18254721Semaste * Any new file which does not already appear in the list is
19314564Sdim * inserted after the current file.
20254721Semaste */
21314564Sdim
22314564Sdim#include "less.h"
23314564Sdim
24314564Sdimextern IFILE	curr_ifile;
25314564Sdim
26314564Sdimstruct ifile {
27314564Sdim	struct ifile *h_next;		/* Links for command line list */
28314564Sdim	struct ifile *h_prev;
29254721Semaste	char *h_filename;		/* Name of the file */
30254721Semaste	void *h_filestate;		/* File state (used in ch.c) */
31314564Sdim	int h_index;			/* Index within command line list */
32314564Sdim	int h_hold;			/* Hold count */
33254721Semaste	char h_opened;			/* Has this ifile been opened? */
34314564Sdim	struct scrpos h_scrpos;		/* Saved position within the file */
35314564Sdim};
36254721Semaste
37314564Sdim/*
38254721Semaste * Convert an IFILE (external representation)
39314564Sdim * to a struct file (internal representation), and vice versa.
40314564Sdim */
41254721Semaste#define int_ifile(h)	((struct ifile *)(h))
42314564Sdim#define ext_ifile(h)	((IFILE)(h))
43314564Sdim
44314564Sdim/*
45344779Sdim * Anchor for linked list.
46254721Semaste */
47314564Sdimstatic struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0',
48254721Semaste				{ NULL_POSITION, 0 } };
49314564Sdimstatic int ifiles = 0;
50314564Sdim
51314564Sdim	static void
52314564Sdimincr_index(p, incr)
53314564Sdim	register struct ifile *p;
54314564Sdim	int incr;
55314564Sdim{
56314564Sdim	for (;  p != &anchor;  p = p->h_next)
57254721Semaste		p->h_index += incr;
58254721Semaste}
59254721Semaste
60254721Semaste/*
61296417Sdim * Link an ifile into the ifile list.
62 */
63	static void
64link_ifile(p, prev)
65	struct ifile *p;
66	struct ifile *prev;
67{
68	/*
69	 * Link into list.
70	 */
71	if (prev == NULL)
72		prev = &anchor;
73	p->h_next = prev->h_next;
74	p->h_prev = prev;
75	prev->h_next->h_prev = p;
76	prev->h_next = p;
77	/*
78	 * Calculate index for the new one,
79	 * and adjust the indexes for subsequent ifiles in the list.
80	 */
81	p->h_index = prev->h_index + 1;
82	incr_index(p->h_next, 1);
83	ifiles++;
84}
85
86/*
87 * Unlink an ifile from the ifile list.
88 */
89	static void
90unlink_ifile(p)
91	struct ifile *p;
92{
93	p->h_next->h_prev = p->h_prev;
94	p->h_prev->h_next = p->h_next;
95	incr_index(p->h_next, -1);
96	ifiles--;
97}
98
99/*
100 * Allocate a new ifile structure and stick a filename in it.
101 * It should go after "prev" in the list
102 * (or at the beginning of the list if "prev" is NULL).
103 * Return a pointer to the new ifile structure.
104 */
105	static struct ifile *
106new_ifile(filename, prev)
107	char *filename;
108	struct ifile *prev;
109{
110	register struct ifile *p;
111
112	/*
113	 * Allocate and initialize structure.
114	 */
115	p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
116	p->h_filename = save(filename);
117	p->h_scrpos.pos = NULL_POSITION;
118	p->h_opened = 0;
119	p->h_hold = 0;
120	p->h_filestate = NULL;
121	link_ifile(p, prev);
122	return (p);
123}
124
125/*
126 * Delete an existing ifile structure.
127 */
128	public void
129del_ifile(h)
130	IFILE h;
131{
132	register struct ifile *p;
133
134	if (h == NULL_IFILE)
135		return;
136	/*
137	 * If the ifile we're deleting is the currently open ifile,
138	 * move off it.
139	 */
140	unmark(h);
141	if (h == curr_ifile)
142		curr_ifile = getoff_ifile(curr_ifile);
143	p = int_ifile(h);
144	unlink_ifile(p);
145	free(p->h_filename);
146	free(p);
147}
148
149/*
150 * Get the ifile after a given one in the list.
151 */
152	public IFILE
153next_ifile(h)
154	IFILE h;
155{
156	register struct ifile *p;
157
158	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
159	if (p->h_next == &anchor)
160		return (NULL_IFILE);
161	return (ext_ifile(p->h_next));
162}
163
164/*
165 * Get the ifile before a given one in the list.
166 */
167	public IFILE
168prev_ifile(h)
169	IFILE h;
170{
171	register struct ifile *p;
172
173	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
174	if (p->h_prev == &anchor)
175		return (NULL_IFILE);
176	return (ext_ifile(p->h_prev));
177}
178
179/*
180 * Return a different ifile from the given one.
181 */
182	public IFILE
183getoff_ifile(ifile)
184	IFILE ifile;
185{
186	IFILE newifile;
187
188	if ((newifile = prev_ifile(ifile)) != NULL_IFILE)
189		return (newifile);
190	if ((newifile = next_ifile(ifile)) != NULL_IFILE)
191		return (newifile);
192	return (NULL_IFILE);
193}
194
195/*
196 * Return the number of ifiles.
197 */
198	public int
199nifile()
200{
201	return (ifiles);
202}
203
204/*
205 * Find an ifile structure, given a filename.
206 */
207	static struct ifile *
208find_ifile(filename)
209	char *filename;
210{
211	register struct ifile *p;
212
213	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
214		if (strcmp(filename, p->h_filename) == 0)
215			return (p);
216	return (NULL);
217}
218
219/*
220 * Get the ifile associated with a filename.
221 * If the filename has not been seen before,
222 * insert the new ifile after "prev" in the list.
223 */
224	public IFILE
225get_ifile(filename, prev)
226	char *filename;
227	IFILE prev;
228{
229	register struct ifile *p;
230
231	if ((p = find_ifile(filename)) == NULL)
232		p = new_ifile(filename, int_ifile(prev));
233	return (ext_ifile(p));
234}
235
236/*
237 * Get the filename associated with a ifile.
238 */
239	public char *
240get_filename(ifile)
241	IFILE ifile;
242{
243	if (ifile == NULL)
244		return (NULL);
245	return (int_ifile(ifile)->h_filename);
246}
247
248/*
249 * Get the index of the file associated with a ifile.
250 */
251	public int
252get_index(ifile)
253	IFILE ifile;
254{
255	return (int_ifile(ifile)->h_index);
256}
257
258/*
259 * Save the file position to be associated with a given file.
260 */
261	public void
262store_pos(ifile, scrpos)
263	IFILE ifile;
264	struct scrpos *scrpos;
265{
266	int_ifile(ifile)->h_scrpos = *scrpos;
267}
268
269/*
270 * Recall the file position associated with a file.
271 * If no position has been associated with the file, return NULL_POSITION.
272 */
273	public void
274get_pos(ifile, scrpos)
275	IFILE ifile;
276	struct scrpos *scrpos;
277{
278	*scrpos = int_ifile(ifile)->h_scrpos;
279}
280
281/*
282 * Mark the ifile as "opened".
283 */
284	public void
285set_open(ifile)
286	IFILE ifile;
287{
288	int_ifile(ifile)->h_opened = 1;
289}
290
291/*
292 * Return whether the ifile has been opened previously.
293 */
294	public int
295opened(ifile)
296	IFILE ifile;
297{
298	return (int_ifile(ifile)->h_opened);
299}
300
301	public void
302hold_ifile(ifile, incr)
303	IFILE ifile;
304	int incr;
305{
306	int_ifile(ifile)->h_hold += incr;
307}
308
309	public int
310held_ifile(ifile)
311	IFILE ifile;
312{
313	return (int_ifile(ifile)->h_hold);
314}
315
316	public void *
317get_filestate(ifile)
318	IFILE ifile;
319{
320	return (int_ifile(ifile)->h_filestate);
321}
322
323	public void
324set_filestate(ifile, filestate)
325	IFILE ifile;
326	void *filestate;
327{
328	int_ifile(ifile)->h_filestate = filestate;
329}
330
331#if 0
332	public void
333if_dump()
334{
335	register struct ifile *p;
336
337	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
338	{
339		printf("%x: %d. <%s> pos %d,%x\n",
340			p, p->h_index, p->h_filename,
341			p->h_scrpos.ln, p->h_scrpos.pos);
342		ch_dump(p->h_filestate);
343	}
344}
345#endif
346