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