1 /* 2 * Copyright (C) 1984-2009 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 347