ifile.c revision 1.1
1/*	$NetBSD	*/
2
3/*
4 * Copyright (C) 1984-2011  Mark Nudelman
5 *
6 * You may distribute under the terms of either the GNU General Public
7 * License or the Less License, as specified in the README file.
8 *
9 * For more information about less, or for information on how to
10 * contact the author, see the README file.
11 */
12
13
14/*
15 * An IFILE represents an input file.
16 *
17 * It is actually a pointer to an ifile structure,
18 * but is opaque outside this module.
19 * Ifile structures are kept in a linked list in the order they
20 * appear on the command line.
21 * Any new file which does not already appear in the list is
22 * inserted after the current file.
23 */
24
25#include "less.h"
26
27extern IFILE	curr_ifile;
28
29struct ifile {
30	struct ifile *h_next;		/* Links for command line list */
31	struct ifile *h_prev;
32	char *h_filename;		/* Name of the file */
33	void *h_filestate;		/* File state (used in ch.c) */
34	int h_index;			/* Index within command line list */
35	int h_hold;			/* Hold count */
36	char h_opened;			/* Has this ifile been opened? */
37	struct scrpos h_scrpos;		/* Saved position within the file */
38};
39
40/*
41 * Convert an IFILE (external representation)
42 * to a struct file (internal representation), and vice versa.
43 */
44#define int_ifile(h)	((struct ifile *)(h))
45#define ext_ifile(h)	((IFILE)(h))
46
47/*
48 * Anchor for linked list.
49 */
50static struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0',
51				{ NULL_POSITION, 0 } };
52static int ifiles = 0;
53
54	static void
55incr_index(p, incr)
56	register struct ifile *p;
57	int incr;
58{
59	for (;  p != &anchor;  p = p->h_next)
60		p->h_index += incr;
61}
62
63/*
64 * Link an ifile into the ifile list.
65 */
66	static void
67link_ifile(p, prev)
68	struct ifile *p;
69	struct ifile *prev;
70{
71	/*
72	 * Link into list.
73	 */
74	if (prev == NULL)
75		prev = &anchor;
76	p->h_next = prev->h_next;
77	p->h_prev = prev;
78	prev->h_next->h_prev = p;
79	prev->h_next = p;
80	/*
81	 * Calculate index for the new one,
82	 * and adjust the indexes for subsequent ifiles in the list.
83	 */
84	p->h_index = prev->h_index + 1;
85	incr_index(p->h_next, 1);
86	ifiles++;
87}
88
89/*
90 * Unlink an ifile from the ifile list.
91 */
92	static void
93unlink_ifile(p)
94	struct ifile *p;
95{
96	p->h_next->h_prev = p->h_prev;
97	p->h_prev->h_next = p->h_next;
98	incr_index(p->h_next, -1);
99	ifiles--;
100}
101
102/*
103 * Allocate a new ifile structure and stick a filename in it.
104 * It should go after "prev" in the list
105 * (or at the beginning of the list if "prev" is NULL).
106 * Return a pointer to the new ifile structure.
107 */
108	static struct ifile *
109new_ifile(filename, prev)
110	char *filename;
111	struct ifile *prev;
112{
113	register struct ifile *p;
114
115	/*
116	 * Allocate and initialize structure.
117	 */
118	p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
119	p->h_filename = save(filename);
120	p->h_scrpos.pos = NULL_POSITION;
121	p->h_opened = 0;
122	p->h_hold = 0;
123	p->h_filestate = NULL;
124	link_ifile(p, prev);
125	return (p);
126}
127
128/*
129 * Delete an existing ifile structure.
130 */
131	public void
132del_ifile(h)
133	IFILE h;
134{
135	register struct ifile *p;
136
137	if (h == NULL_IFILE)
138		return;
139	/*
140	 * If the ifile we're deleting is the currently open ifile,
141	 * move off it.
142	 */
143	unmark(h);
144	if (h == curr_ifile)
145		curr_ifile = getoff_ifile(curr_ifile);
146	p = int_ifile(h);
147	unlink_ifile(p);
148	free(p->h_filename);
149	free(p);
150}
151
152/*
153 * Get the ifile after a given one in the list.
154 */
155	public IFILE
156next_ifile(h)
157	IFILE h;
158{
159	register struct ifile *p;
160
161	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
162	if (p->h_next == &anchor)
163		return (NULL_IFILE);
164	return (ext_ifile(p->h_next));
165}
166
167/*
168 * Get the ifile before a given one in the list.
169 */
170	public IFILE
171prev_ifile(h)
172	IFILE h;
173{
174	register struct ifile *p;
175
176	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
177	if (p->h_prev == &anchor)
178		return (NULL_IFILE);
179	return (ext_ifile(p->h_prev));
180}
181
182/*
183 * Return a different ifile from the given one.
184 */
185	public IFILE
186getoff_ifile(ifile)
187	IFILE ifile;
188{
189	IFILE newifile;
190
191	if ((newifile = prev_ifile(ifile)) != NULL_IFILE)
192		return (newifile);
193	if ((newifile = next_ifile(ifile)) != NULL_IFILE)
194		return (newifile);
195	return (NULL_IFILE);
196}
197
198/*
199 * Return the number of ifiles.
200 */
201	public int
202nifile()
203{
204	return (ifiles);
205}
206
207/*
208 * Find an ifile structure, given a filename.
209 */
210	static struct ifile *
211find_ifile(filename)
212	char *filename;
213{
214	register struct ifile *p;
215
216	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
217		if (strcmp(filename, p->h_filename) == 0)
218			return (p);
219	return (NULL);
220}
221
222/*
223 * Get the ifile associated with a filename.
224 * If the filename has not been seen before,
225 * insert the new ifile after "prev" in the list.
226 */
227	public IFILE
228get_ifile(filename, prev)
229	char *filename;
230	IFILE prev;
231{
232	register struct ifile *p;
233
234	if ((p = find_ifile(filename)) == NULL)
235		p = new_ifile(filename, int_ifile(prev));
236	return (ext_ifile(p));
237}
238
239/*
240 * Get the filename associated with a ifile.
241 */
242	public char *
243get_filename(ifile)
244	IFILE ifile;
245{
246	if (ifile == NULL)
247		return (NULL);
248	return (int_ifile(ifile)->h_filename);
249}
250
251/*
252 * Get the index of the file associated with a ifile.
253 */
254	public int
255get_index(ifile)
256	IFILE ifile;
257{
258	return (int_ifile(ifile)->h_index);
259}
260
261/*
262 * Save the file position to be associated with a given file.
263 */
264	public void
265store_pos(ifile, scrpos)
266	IFILE ifile;
267	struct scrpos *scrpos;
268{
269	int_ifile(ifile)->h_scrpos = *scrpos;
270}
271
272/*
273 * Recall the file position associated with a file.
274 * If no position has been associated with the file, return NULL_POSITION.
275 */
276	public void
277get_pos(ifile, scrpos)
278	IFILE ifile;
279	struct scrpos *scrpos;
280{
281	*scrpos = int_ifile(ifile)->h_scrpos;
282}
283
284/*
285 * Mark the ifile as "opened".
286 */
287	public void
288set_open(ifile)
289	IFILE ifile;
290{
291	int_ifile(ifile)->h_opened = 1;
292}
293
294/*
295 * Return whether the ifile has been opened previously.
296 */
297	public int
298opened(ifile)
299	IFILE ifile;
300{
301	return (int_ifile(ifile)->h_opened);
302}
303
304	public void
305hold_ifile(ifile, incr)
306	IFILE ifile;
307	int incr;
308{
309	int_ifile(ifile)->h_hold += incr;
310}
311
312	public int
313held_ifile(ifile)
314	IFILE ifile;
315{
316	return (int_ifile(ifile)->h_hold);
317}
318
319	public void *
320get_filestate(ifile)
321	IFILE ifile;
322{
323	return (int_ifile(ifile)->h_filestate);
324}
325
326	public void
327set_filestate(ifile, filestate)
328	IFILE ifile;
329	void *filestate;
330{
331	int_ifile(ifile)->h_filestate = filestate;
332}
333
334#if 0
335	public void
336if_dump()
337{
338	register struct ifile *p;
339
340	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
341	{
342		printf("%x: %d. <%s> pos %d,%x\n",
343			p, p->h_index, p->h_filename,
344			p->h_scrpos.ln, p->h_scrpos.pos);
345		ch_dump(p->h_filestate);
346	}
347}
348#endif
349