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