1 /* 2 * Copyright (C) 1984-2020 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 /* 125 * {{ It's dodgy to call mark.c functions from here; 126 * there is potentially dangerous recursion. 127 * Probably need to revisit this design. }} 128 */ 129 mark_check_ifile(ext_ifile(p)); 130 return (p); 131 } 132 133 /* 134 * Delete an existing ifile structure. 135 */ 136 public void 137 del_ifile(h) 138 IFILE h; 139 { 140 struct ifile *p; 141 142 if (h == NULL_IFILE) 143 return; 144 /* 145 * If the ifile we're deleting is the currently open ifile, 146 * move off it. 147 */ 148 unmark(h); 149 if (h == curr_ifile) 150 curr_ifile = getoff_ifile(curr_ifile); 151 p = int_ifile(h); 152 unlink_ifile(p); 153 free(p->h_filename); 154 free(p); 155 } 156 157 /* 158 * Get the ifile after a given one in the list. 159 */ 160 public IFILE 161 next_ifile(h) 162 IFILE h; 163 { 164 struct ifile *p; 165 166 p = (h == NULL_IFILE) ? &anchor : int_ifile(h); 167 if (p->h_next == &anchor) 168 return (NULL_IFILE); 169 return (ext_ifile(p->h_next)); 170 } 171 172 /* 173 * Get the ifile before a given one in the list. 174 */ 175 public IFILE 176 prev_ifile(h) 177 IFILE h; 178 { 179 struct ifile *p; 180 181 p = (h == NULL_IFILE) ? &anchor : int_ifile(h); 182 if (p->h_prev == &anchor) 183 return (NULL_IFILE); 184 return (ext_ifile(p->h_prev)); 185 } 186 187 /* 188 * Return a different ifile from the given one. 189 */ 190 public IFILE 191 getoff_ifile(ifile) 192 IFILE ifile; 193 { 194 IFILE newifile; 195 196 if ((newifile = prev_ifile(ifile)) != NULL_IFILE) 197 return (newifile); 198 if ((newifile = next_ifile(ifile)) != NULL_IFILE) 199 return (newifile); 200 return (NULL_IFILE); 201 } 202 203 /* 204 * Return the number of ifiles. 205 */ 206 public int 207 nifile(VOID_PARAM) 208 { 209 return (ifiles); 210 } 211 212 /* 213 * Find an ifile structure, given a filename. 214 */ 215 static struct ifile * 216 find_ifile(filename) 217 char *filename; 218 { 219 struct ifile *p; 220 char *rfilename = lrealpath(filename); 221 222 for (p = anchor.h_next; p != &anchor; p = p->h_next) 223 { 224 if (strcmp(filename, p->h_filename) == 0 || 225 strcmp(rfilename, p->h_filename) == 0) 226 { 227 /* 228 * If given name is shorter than the name we were 229 * previously using for this file, adopt shorter name. 230 */ 231 if (strlen(filename) < strlen(p->h_filename)) 232 strcpy(p->h_filename, filename); 233 break; 234 } 235 } 236 free(rfilename); 237 if (p == &anchor) 238 p = NULL; 239 return (p); 240 } 241 242 /* 243 * Get the ifile associated with a filename. 244 * If the filename has not been seen before, 245 * insert the new ifile after "prev" in the list. 246 */ 247 public IFILE 248 get_ifile(filename, prev) 249 char *filename; 250 IFILE prev; 251 { 252 struct ifile *p; 253 254 if ((p = find_ifile(filename)) == NULL) 255 p = new_ifile(filename, int_ifile(prev)); 256 return (ext_ifile(p)); 257 } 258 259 /* 260 * Get the filename associated with a ifile. 261 */ 262 public char * 263 get_filename(ifile) 264 IFILE ifile; 265 { 266 if (ifile == NULL) 267 return (NULL); 268 return (int_ifile(ifile)->h_filename); 269 } 270 271 /* 272 * Get the index of the file associated with a ifile. 273 */ 274 public int 275 get_index(ifile) 276 IFILE ifile; 277 { 278 return (int_ifile(ifile)->h_index); 279 } 280 281 /* 282 * Save the file position to be associated with a given file. 283 */ 284 public void 285 store_pos(ifile, scrpos) 286 IFILE ifile; 287 struct scrpos *scrpos; 288 { 289 int_ifile(ifile)->h_scrpos = *scrpos; 290 } 291 292 /* 293 * Recall the file position associated with a file. 294 * If no position has been associated with the file, return NULL_POSITION. 295 */ 296 public void 297 get_pos(ifile, scrpos) 298 IFILE ifile; 299 struct scrpos *scrpos; 300 { 301 *scrpos = int_ifile(ifile)->h_scrpos; 302 } 303 304 /* 305 * Mark the ifile as "opened". 306 */ 307 public void 308 set_open(ifile) 309 IFILE ifile; 310 { 311 int_ifile(ifile)->h_opened = 1; 312 } 313 314 /* 315 * Return whether the ifile has been opened previously. 316 */ 317 public int 318 opened(ifile) 319 IFILE ifile; 320 { 321 return (int_ifile(ifile)->h_opened); 322 } 323 324 public void 325 hold_ifile(ifile, incr) 326 IFILE ifile; 327 int incr; 328 { 329 int_ifile(ifile)->h_hold += incr; 330 } 331 332 public int 333 held_ifile(ifile) 334 IFILE ifile; 335 { 336 return (int_ifile(ifile)->h_hold); 337 } 338 339 public void * 340 get_filestate(ifile) 341 IFILE ifile; 342 { 343 return (int_ifile(ifile)->h_filestate); 344 } 345 346 public void 347 set_filestate(ifile, filestate) 348 IFILE ifile; 349 void *filestate; 350 { 351 int_ifile(ifile)->h_filestate = filestate; 352 } 353 354 public void 355 set_altpipe(ifile, p) 356 IFILE ifile; 357 void *p; 358 { 359 int_ifile(ifile)->h_altpipe = p; 360 } 361 362 public void * 363 get_altpipe(ifile) 364 IFILE ifile; 365 { 366 return (int_ifile(ifile)->h_altpipe); 367 } 368 369 public void 370 set_altfilename(ifile, altfilename) 371 IFILE ifile; 372 char *altfilename; 373 { 374 struct ifile *p = int_ifile(ifile); 375 if (p->h_altfilename != NULL) 376 free(p->h_altfilename); 377 p->h_altfilename = altfilename; 378 } 379 380 public char * 381 get_altfilename(ifile) 382 IFILE ifile; 383 { 384 return (int_ifile(ifile)->h_altfilename); 385 } 386 387 #if 0 388 public void 389 if_dump(VOID_PARAM) 390 { 391 struct ifile *p; 392 393 for (p = anchor.h_next; p != &anchor; p = p->h_next) 394 { 395 printf("%x: %d. <%s> pos %d,%x\n", 396 p, p->h_index, p->h_filename, 397 p->h_scrpos.ln, p->h_scrpos.pos); 398 ch_dump(p->h_filestate); 399 } 400 } 401 #endif 402