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