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