xref: /netbsd-src/external/bsd/less/dist/ifile.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
1 /*	$NetBSD: ifile.c,v 1.3 2011/07/03 20:14:12 tron Exp $	*/
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 
27 extern IFILE	curr_ifile;
28 
29 struct 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  */
50 static struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0',
51 				{ NULL_POSITION, 0 } };
52 static int ifiles = 0;
53 
54 static void incr_index __P((struct ifile *, int));
55 static void link_ifile __P((struct ifile *, struct ifile *));
56 static void unlink_ifile __P((struct ifile *));
57 static struct ifile *new_ifile __P((char *, struct ifile *));
58 static struct ifile *find_ifile __P((char *));
59 
60 	static void
61 incr_index(p, incr)
62 	register struct ifile *p;
63 	int incr;
64 {
65 	for (;  p != &anchor;  p = p->h_next)
66 		p->h_index += incr;
67 }
68 
69 /*
70  * Link an ifile into the ifile list.
71  */
72 	static void
73 link_ifile(p, prev)
74 	struct ifile *p;
75 	struct ifile *prev;
76 {
77 	/*
78 	 * Link into list.
79 	 */
80 	if (prev == NULL)
81 		prev = &anchor;
82 	p->h_next = prev->h_next;
83 	p->h_prev = prev;
84 	prev->h_next->h_prev = p;
85 	prev->h_next = p;
86 	/*
87 	 * Calculate index for the new one,
88 	 * and adjust the indexes for subsequent ifiles in the list.
89 	 */
90 	p->h_index = prev->h_index + 1;
91 	incr_index(p->h_next, 1);
92 	ifiles++;
93 }
94 
95 /*
96  * Unlink an ifile from the ifile list.
97  */
98 	static void
99 unlink_ifile(p)
100 	struct ifile *p;
101 {
102 	p->h_next->h_prev = p->h_prev;
103 	p->h_prev->h_next = p->h_next;
104 	incr_index(p->h_next, -1);
105 	ifiles--;
106 }
107 
108 /*
109  * Allocate a new ifile structure and stick a filename in it.
110  * It should go after "prev" in the list
111  * (or at the beginning of the list if "prev" is NULL).
112  * Return a pointer to the new ifile structure.
113  */
114 	static struct ifile *
115 new_ifile(filename, prev)
116 	char *filename;
117 	struct ifile *prev;
118 {
119 	register struct ifile *p;
120 
121 	/*
122 	 * Allocate and initialize structure.
123 	 */
124 	p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
125 	p->h_filename = save(filename);
126 	p->h_scrpos.pos = NULL_POSITION;
127 	p->h_opened = 0;
128 	p->h_hold = 0;
129 	p->h_filestate = NULL;
130 	link_ifile(p, prev);
131 	return (p);
132 }
133 
134 /*
135  * Delete an existing ifile structure.
136  */
137 	public void
138 del_ifile(h)
139 	IFILE h;
140 {
141 	register struct ifile *p;
142 
143 	if (h == NULL_IFILE)
144 		return;
145 	/*
146 	 * If the ifile we're deleting is the currently open ifile,
147 	 * move off it.
148 	 */
149 	unmark(h);
150 	if (h == curr_ifile)
151 		curr_ifile = getoff_ifile(curr_ifile);
152 	p = int_ifile(h);
153 	unlink_ifile(p);
154 	free(p->h_filename);
155 	free(p);
156 }
157 
158 /*
159  * Get the ifile after a given one in the list.
160  */
161 	public IFILE
162 next_ifile(h)
163 	IFILE h;
164 {
165 	register struct ifile *p;
166 
167 	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
168 	if (p->h_next == &anchor)
169 		return (NULL_IFILE);
170 	return (ext_ifile(p->h_next));
171 }
172 
173 /*
174  * Get the ifile before a given one in the list.
175  */
176 	public IFILE
177 prev_ifile(h)
178 	IFILE h;
179 {
180 	register struct ifile *p;
181 
182 	p = (h == NULL_IFILE) ? &anchor : int_ifile(h);
183 	if (p->h_prev == &anchor)
184 		return (NULL_IFILE);
185 	return (ext_ifile(p->h_prev));
186 }
187 
188 /*
189  * Return a different ifile from the given one.
190  */
191 	public IFILE
192 getoff_ifile(ifile)
193 	IFILE ifile;
194 {
195 	IFILE newifile;
196 
197 	if ((newifile = prev_ifile(ifile)) != NULL_IFILE)
198 		return (newifile);
199 	if ((newifile = next_ifile(ifile)) != NULL_IFILE)
200 		return (newifile);
201 	return (NULL_IFILE);
202 }
203 
204 /*
205  * Return the number of ifiles.
206  */
207 	public int
208 nifile()
209 {
210 	return (ifiles);
211 }
212 
213 /*
214  * Find an ifile structure, given a filename.
215  */
216 	static struct ifile *
217 find_ifile(filename)
218 	char *filename;
219 {
220 	register struct ifile *p;
221 
222 	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
223 		if (strcmp(filename, p->h_filename) == 0)
224 			return (p);
225 	return (NULL);
226 }
227 
228 /*
229  * Get the ifile associated with a filename.
230  * If the filename has not been seen before,
231  * insert the new ifile after "prev" in the list.
232  */
233 	public IFILE
234 get_ifile(filename, prev)
235 	char *filename;
236 	IFILE prev;
237 {
238 	register struct ifile *p;
239 
240 	if ((p = find_ifile(filename)) == NULL)
241 		p = new_ifile(filename, int_ifile(prev));
242 	return (ext_ifile(p));
243 }
244 
245 /*
246  * Get the filename associated with a ifile.
247  */
248 	public char *
249 get_filename(ifile)
250 	IFILE ifile;
251 {
252 	if (ifile == NULL)
253 		return (NULL);
254 	return (int_ifile(ifile)->h_filename);
255 }
256 
257 /*
258  * Get the index of the file associated with a ifile.
259  */
260 	public int
261 get_index(ifile)
262 	IFILE ifile;
263 {
264 	return (int_ifile(ifile)->h_index);
265 }
266 
267 /*
268  * Save the file position to be associated with a given file.
269  */
270 	public void
271 store_pos(ifile, scrpos)
272 	IFILE ifile;
273 	struct scrpos *scrpos;
274 {
275 	int_ifile(ifile)->h_scrpos = *scrpos;
276 }
277 
278 /*
279  * Recall the file position associated with a file.
280  * If no position has been associated with the file, return NULL_POSITION.
281  */
282 	public void
283 get_pos(ifile, scrpos)
284 	IFILE ifile;
285 	struct scrpos *scrpos;
286 {
287 	*scrpos = int_ifile(ifile)->h_scrpos;
288 }
289 
290 /*
291  * Mark the ifile as "opened".
292  */
293 	public void
294 set_open(ifile)
295 	IFILE ifile;
296 {
297 	int_ifile(ifile)->h_opened = 1;
298 }
299 
300 /*
301  * Return whether the ifile has been opened previously.
302  */
303 	public int
304 opened(ifile)
305 	IFILE ifile;
306 {
307 	return (int_ifile(ifile)->h_opened);
308 }
309 
310 	public void
311 hold_ifile(ifile, incr)
312 	IFILE ifile;
313 	int incr;
314 {
315 	int_ifile(ifile)->h_hold += incr;
316 }
317 
318 	public int
319 held_ifile(ifile)
320 	IFILE ifile;
321 {
322 	return (int_ifile(ifile)->h_hold);
323 }
324 
325 	public void *
326 get_filestate(ifile)
327 	IFILE ifile;
328 {
329 	return (int_ifile(ifile)->h_filestate);
330 }
331 
332 	public void
333 set_filestate(ifile, filestate)
334 	IFILE ifile;
335 	void *filestate;
336 {
337 	int_ifile(ifile)->h_filestate = filestate;
338 }
339 
340 #if 0
341 	public void
342 if_dump()
343 {
344 	register struct ifile *p;
345 
346 	for (p = anchor.h_next;  p != &anchor;  p = p->h_next)
347 	{
348 		printf("%x: %d. <%s> pos %d,%x\n",
349 			p, p->h_index, p->h_filename,
350 			p->h_scrpos.ln, p->h_scrpos.pos);
351 		ch_dump(p->h_filestate);
352 	}
353 }
354 #endif
355