1 |
|
|
/* |
2 |
|
|
* Copyright (C) 1984-2012 Mark Nudelman |
3 |
|
|
* Modified for use with illumos by Garrett D'Amore. |
4 |
|
|
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
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, see the README file. |
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 |
|
|
{ -1, 0 } }; |
50 |
|
|
static int ifiles = 0; |
51 |
|
|
|
52 |
|
|
static void |
53 |
|
|
incr_index(struct ifile *p, int incr) |
54 |
|
|
{ |
55 |
✗✓ |
123 |
for (; p != &anchor; p = p->h_next) |
56 |
|
|
p->h_index += incr; |
57 |
|
41 |
} |
58 |
|
|
|
59 |
|
|
/* |
60 |
|
|
* Link an ifile into the ifile list. |
61 |
|
|
*/ |
62 |
|
|
static void |
63 |
|
|
link_ifile(struct ifile *p, struct ifile *prev) |
64 |
|
|
{ |
65 |
|
|
/* |
66 |
|
|
* Link into list. |
67 |
|
|
*/ |
68 |
|
78 |
if (prev == NULL) |
69 |
|
|
prev = &anchor; |
70 |
|
39 |
p->h_next = prev->h_next; |
71 |
|
39 |
p->h_prev = prev; |
72 |
|
39 |
prev->h_next->h_prev = p; |
73 |
|
39 |
prev->h_next = p; |
74 |
|
|
/* |
75 |
|
|
* Calculate index for the new one, |
76 |
|
|
* and adjust the indexes for subsequent ifiles in the list. |
77 |
|
|
*/ |
78 |
|
39 |
p->h_index = prev->h_index + 1; |
79 |
|
39 |
incr_index(p->h_next, 1); |
80 |
|
39 |
ifiles++; |
81 |
|
39 |
} |
82 |
|
|
|
83 |
|
|
/* |
84 |
|
|
* Unlink an ifile from the ifile list. |
85 |
|
|
*/ |
86 |
|
|
static void |
87 |
|
|
unlink_ifile(struct ifile *p) |
88 |
|
|
{ |
89 |
|
4 |
p->h_next->h_prev = p->h_prev; |
90 |
|
2 |
p->h_prev->h_next = p->h_next; |
91 |
|
2 |
incr_index(p->h_next, -1); |
92 |
|
2 |
ifiles--; |
93 |
|
2 |
} |
94 |
|
|
|
95 |
|
|
/* |
96 |
|
|
* Allocate a new ifile structure and stick a filename in it. |
97 |
|
|
* It should go after "prev" in the list |
98 |
|
|
* (or at the beginning of the list if "prev" is NULL). |
99 |
|
|
* Return a pointer to the new ifile structure. |
100 |
|
|
*/ |
101 |
|
|
static struct ifile * |
102 |
|
|
new_ifile(char *filename, struct ifile *prev) |
103 |
|
|
{ |
104 |
|
|
struct ifile *p; |
105 |
|
|
|
106 |
|
|
/* |
107 |
|
|
* Allocate and initialize structure. |
108 |
|
|
*/ |
109 |
|
78 |
p = ecalloc(1, sizeof (struct ifile)); |
110 |
|
39 |
p->h_filename = estrdup(filename); |
111 |
|
39 |
p->h_scrpos.pos = -1; |
112 |
|
39 |
p->h_opened = 0; |
113 |
|
39 |
p->h_hold = 0; |
114 |
|
39 |
p->h_filestate = NULL; |
115 |
|
39 |
link_ifile(p, prev); |
116 |
|
39 |
return (p); |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
/* |
120 |
|
|
* Delete an existing ifile structure. |
121 |
|
|
*/ |
122 |
|
|
void |
123 |
|
|
del_ifile(IFILE h) |
124 |
|
|
{ |
125 |
|
|
struct ifile *p; |
126 |
|
|
|
127 |
✗✓ |
4 |
if (h == NULL) |
128 |
|
|
return; |
129 |
|
|
/* |
130 |
|
|
* If the ifile we're deleting is the currently open ifile, |
131 |
|
|
* move off it. |
132 |
|
|
*/ |
133 |
|
2 |
unmark(h); |
134 |
✗✓ |
2 |
if (h == curr_ifile) |
135 |
|
|
curr_ifile = getoff_ifile(curr_ifile); |
136 |
|
2 |
p = int_ifile(h); |
137 |
|
2 |
unlink_ifile(p); |
138 |
|
2 |
free(p->h_filename); |
139 |
|
2 |
free(p); |
140 |
|
4 |
} |
141 |
|
|
|
142 |
|
|
/* |
143 |
|
|
* Get the ifile after a given one in the list. |
144 |
|
|
*/ |
145 |
|
|
IFILE |
146 |
|
|
next_ifile(IFILE h) |
147 |
|
|
{ |
148 |
|
|
struct ifile *p; |
149 |
|
|
|
150 |
|
196 |
p = (h == NULL) ? &anchor : int_ifile(h); |
151 |
✓✓ |
98 |
if (p->h_next == &anchor) |
152 |
|
71 |
return (NULL); |
153 |
|
27 |
return (ext_ifile(p->h_next)); |
154 |
|
98 |
} |
155 |
|
|
|
156 |
|
|
/* |
157 |
|
|
* Get the ifile before a given one in the list. |
158 |
|
|
*/ |
159 |
|
|
IFILE |
160 |
|
|
prev_ifile(IFILE h) |
161 |
|
|
{ |
162 |
|
|
struct ifile *p; |
163 |
|
|
|
164 |
|
58 |
p = (h == NULL) ? &anchor : int_ifile(h); |
165 |
✓✓ |
29 |
if (p->h_prev == &anchor) |
166 |
|
2 |
return (NULL); |
167 |
|
27 |
return (ext_ifile(p->h_prev)); |
168 |
|
29 |
} |
169 |
|
|
|
170 |
|
|
/* |
171 |
|
|
* Return a different ifile from the given one. |
172 |
|
|
*/ |
173 |
|
|
IFILE |
174 |
|
|
getoff_ifile(IFILE ifile) |
175 |
|
|
{ |
176 |
|
|
IFILE newifile; |
177 |
|
|
|
178 |
|
|
if ((newifile = prev_ifile(ifile)) != NULL) |
179 |
|
|
return (newifile); |
180 |
|
|
if ((newifile = next_ifile(ifile)) != NULL) |
181 |
|
|
return (newifile); |
182 |
|
|
return (NULL); |
183 |
|
|
} |
184 |
|
|
|
185 |
|
|
/* |
186 |
|
|
* Return the number of ifiles. |
187 |
|
|
*/ |
188 |
|
|
int |
189 |
|
|
nifile(void) |
190 |
|
|
{ |
191 |
|
142 |
return (ifiles); |
192 |
|
|
} |
193 |
|
|
|
194 |
|
|
/* |
195 |
|
|
* Find an ifile structure, given a filename. |
196 |
|
|
*/ |
197 |
|
|
static struct ifile * |
198 |
|
|
find_ifile(const char *filename) |
199 |
|
|
{ |
200 |
|
|
struct ifile *p; |
201 |
|
|
|
202 |
✗✓ |
117 |
for (p = anchor.h_next; p != &anchor; p = p->h_next) |
203 |
|
|
if (strcmp(filename, p->h_filename) == 0) |
204 |
|
|
return (p); |
205 |
|
39 |
return (NULL); |
206 |
|
39 |
} |
207 |
|
|
|
208 |
|
|
/* |
209 |
|
|
* Get the ifile associated with a filename. |
210 |
|
|
* If the filename has not been seen before, |
211 |
|
|
* insert the new ifile after "prev" in the list. |
212 |
|
|
*/ |
213 |
|
|
IFILE |
214 |
|
|
get_ifile(char *filename, IFILE prev) |
215 |
|
|
{ |
216 |
|
|
struct ifile *p; |
217 |
|
|
|
218 |
✓✗ |
78 |
if ((p = find_ifile(filename)) == NULL) |
219 |
|
39 |
p = new_ifile(filename, int_ifile(prev)); |
220 |
|
39 |
return (ext_ifile(p)); |
221 |
|
|
} |
222 |
|
|
|
223 |
|
|
/* |
224 |
|
|
* Get the filename associated with a ifile. |
225 |
|
|
*/ |
226 |
|
|
char * |
227 |
|
|
get_filename(IFILE ifile) |
228 |
|
|
{ |
229 |
✗✓ |
318 |
if (ifile == NULL) |
230 |
|
|
return (NULL); |
231 |
|
159 |
return (int_ifile(ifile)->h_filename); |
232 |
|
159 |
} |
233 |
|
|
|
234 |
|
|
/* |
235 |
|
|
* Get the index of the file associated with a ifile. |
236 |
|
|
*/ |
237 |
|
|
int |
238 |
|
|
get_index(IFILE ifile) |
239 |
|
|
{ |
240 |
|
|
return (int_ifile(ifile)->h_index); |
241 |
|
|
} |
242 |
|
|
|
243 |
|
|
/* |
244 |
|
|
* Save the file position to be associated with a given file. |
245 |
|
|
*/ |
246 |
|
|
void |
247 |
|
|
store_pos(IFILE ifile, struct scrpos *scrpos) |
248 |
|
|
{ |
249 |
|
74 |
int_ifile(ifile)->h_scrpos = *scrpos; |
250 |
|
37 |
} |
251 |
|
|
|
252 |
|
|
/* |
253 |
|
|
* Recall the file position associated with a file. |
254 |
|
|
* If no position has been associated with the file, return -1. |
255 |
|
|
*/ |
256 |
|
|
void |
257 |
|
|
get_pos(IFILE ifile, struct scrpos *scrpos) |
258 |
|
|
{ |
259 |
|
74 |
*scrpos = int_ifile(ifile)->h_scrpos; |
260 |
|
37 |
} |
261 |
|
|
|
262 |
|
|
/* |
263 |
|
|
* Mark the ifile as "opened". |
264 |
|
|
*/ |
265 |
|
|
void |
266 |
|
|
set_open(IFILE ifile) |
267 |
|
|
{ |
268 |
|
74 |
int_ifile(ifile)->h_opened = 1; |
269 |
|
37 |
} |
270 |
|
|
|
271 |
|
|
/* |
272 |
|
|
* Return whether the ifile has been opened previously. |
273 |
|
|
*/ |
274 |
|
|
int |
275 |
|
|
opened(IFILE ifile) |
276 |
|
|
{ |
277 |
|
50 |
return (int_ifile(ifile)->h_opened); |
278 |
|
|
} |
279 |
|
|
|
280 |
|
|
void |
281 |
|
|
hold_ifile(IFILE ifile, int incr) |
282 |
|
|
{ |
283 |
|
192 |
int_ifile(ifile)->h_hold += incr; |
284 |
|
96 |
} |
285 |
|
|
|
286 |
|
|
int |
287 |
|
|
held_ifile(IFILE ifile) |
288 |
|
|
{ |
289 |
|
|
return (int_ifile(ifile)->h_hold); |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
void * |
293 |
|
|
get_filestate(IFILE ifile) |
294 |
|
|
{ |
295 |
|
74 |
return (int_ifile(ifile)->h_filestate); |
296 |
|
|
} |
297 |
|
|
|
298 |
|
|
void |
299 |
|
|
set_filestate(IFILE ifile, void *filestate) |
300 |
|
|
{ |
301 |
|
124 |
int_ifile(ifile)->h_filestate = filestate; |
302 |
|
62 |
} |