1/* 2 * Copyright (C) 1984-2012 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}; 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 */ 47static struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0', 48 { NULL_POSITION, 0 } }; 49static int ifiles = 0; 50 51 static void 52incr_index(p, incr) 53 register 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 64link_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 90unlink_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 * 106new_ifile(filename, prev) 107 char *filename; 108 struct ifile *prev; 109{ 110 register 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 129del_ifile(h) 130 IFILE h; 131{ 132 register 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 153next_ifile(h) 154 IFILE h; 155{ 156 register 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 168prev_ifile(h) 169 IFILE h; 170{ 171 register 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 183getoff_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 199nifile() 200{ 201 return (ifiles); 202} 203 204/* 205 * Find an ifile structure, given a filename. 206 */ 207 static struct ifile * 208find_ifile(filename) 209 char *filename; 210{ 211 register 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 225get_ifile(filename, prev) 226 char *filename; 227 IFILE prev; 228{ 229 register 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 * 240get_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 252get_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 262store_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 274get_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 285set_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 295opened(ifile) 296 IFILE ifile; 297{ 298 return (int_ifile(ifile)->h_opened); 299} 300 301 public void 302hold_ifile(ifile, incr) 303 IFILE ifile; 304 int incr; 305{ 306 int_ifile(ifile)->h_hold += incr; 307} 308 309 public int 310held_ifile(ifile) 311 IFILE ifile; 312{ 313 return (int_ifile(ifile)->h_hold); 314} 315 316 public void * 317get_filestate(ifile) 318 IFILE ifile; 319{ 320 return (int_ifile(ifile)->h_filestate); 321} 322 323 public void 324set_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 333if_dump() 334{ 335 register 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