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 24extern IFILE curr_ifile; 25 26struct 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 */ 49static struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0', 50 { NULL_POSITION, 0 } }; 51static int ifiles = 0; 52 53 static void 54incr_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 66link_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 92unlink_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 * 108new_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 131del_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 155next_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 170prev_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 185getoff_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 201nifile() 202{ 203 return (ifiles); 204} 205 206/* 207 * Find an ifile structure, given a filename. 208 */ 209 static struct ifile * 210find_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 227get_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 * 242get_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 254get_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 264store_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 276get_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 287set_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 297opened(ifile) 298 IFILE ifile; 299{ 300 return (int_ifile(ifile)->h_opened); 301} 302 303 public void 304hold_ifile(ifile, incr) 305 IFILE ifile; 306 int incr; 307{ 308 int_ifile(ifile)->h_hold += incr; 309} 310 311 public int 312held_ifile(ifile) 313 IFILE ifile; 314{ 315 return (int_ifile(ifile)->h_hold); 316} 317 318 public void * 319get_filestate(ifile) 320 IFILE ifile; 321{ 322 return (int_ifile(ifile)->h_filestate); 323} 324 325 public void 326set_filestate(ifile, filestate) 327 IFILE ifile; 328 void *filestate; 329{ 330 int_ifile(ifile)->h_filestate = filestate; 331} 332 333 public void 334set_altpipe(ifile, p) 335 IFILE ifile; 336 void *p; 337{ 338 int_ifile(ifile)->h_altpipe = p; 339} 340 341 public void * 342get_altpipe(ifile) 343 IFILE ifile; 344{ 345 return (int_ifile(ifile)->h_altpipe); 346} 347 348 public void 349set_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 * 360get_altfilename(ifile) 361 IFILE ifile; 362{ 363 return (int_ifile(ifile)->h_altfilename); 364} 365 366#if 0 367 public void 368if_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