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