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