1 /* 2 * Copyright (C) 1984-2012 Mark Nudelman 3 * Modified for use with illumos by Garrett D'Amore. 4 * Copyright 2014 Garrett D'Amore <garrett@damore.org> 5 * 6 * You may distribute under the terms of either the GNU General Public 7 * License or the Less License, as specified in the README file. 8 * 9 * For more information, see the README file. 10 */ 11 12 /* 13 * An IFILE represents an input file. 14 * 15 * It is actually a pointer to an ifile structure, 16 * but is opaque outside this module. 17 * Ifile structures are kept in a linked list in the order they 18 * appear on the command line. 19 * Any new file which does not already appear in the list is 20 * inserted after the current file. 21 */ 22 23 #include "less.h" 24 25 extern IFILE curr_ifile; 26 27 struct ifile { 28 struct ifile *h_next; /* Links for command line list */ 29 struct ifile *h_prev; 30 char *h_filename; /* 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 }; 37 38 /* 39 * Convert an IFILE (external representation) 40 * to a struct file (internal representation), and vice versa. 41 */ 42 #define int_ifile(h) ((struct ifile *)(h)) 43 #define ext_ifile(h) ((IFILE)(h)) 44 45 /* 46 * Anchor for linked list. 47 */ 48 static struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0', 49 { -1, 0 } }; 50 static int ifiles = 0; 51 52 static void 53 incr_index(struct ifile *p, int incr) 54 { 55 for (; p != &anchor; p = p->h_next) 56 p->h_index += incr; 57 } 58 59 /* 60 * Link an ifile into the ifile list. 61 */ 62 static void 63 link_ifile(struct ifile *p, struct ifile *prev) 64 { 65 /* 66 * Link into list. 67 */ 68 if (prev == NULL) 69 prev = &anchor; 70 p->h_next = prev->h_next; 71 p->h_prev = prev; 72 prev->h_next->h_prev = p; 73 prev->h_next = p; 74 /* 75 * Calculate index for the new one, 76 * and adjust the indexes for subsequent ifiles in the list. 77 */ 78 p->h_index = prev->h_index + 1; 79 incr_index(p->h_next, 1); 80 ifiles++; 81 } 82 83 /* 84 * Unlink an ifile from the ifile list. 85 */ 86 static void 87 unlink_ifile(struct ifile *p) 88 { 89 p->h_next->h_prev = p->h_prev; 90 p->h_prev->h_next = p->h_next; 91 incr_index(p->h_next, -1); 92 ifiles--; 93 } 94 95 /* 96 * Allocate a new ifile structure and stick a filename in it. 97 * It should go after "prev" in the list 98 * (or at the beginning of the list if "prev" is NULL). 99 * Return a pointer to the new ifile structure. 100 */ 101 static struct ifile * 102 new_ifile(char *filename, struct ifile *prev) 103 { 104 struct ifile *p; 105 106 /* 107 * Allocate and initialize structure. 108 */ 109 p = ecalloc(1, sizeof (struct ifile)); 110 p->h_filename = estrdup(filename); 111 p->h_scrpos.pos = -1; 112 p->h_opened = 0; 113 p->h_hold = 0; 114 p->h_filestate = NULL; 115 link_ifile(p, prev); 116 return (p); 117 } 118 119 /* 120 * Delete an existing ifile structure. 121 */ 122 void 123 del_ifile(IFILE h) 124 { 125 struct ifile *p; 126 127 if (h == NULL) 128 return; 129 /* 130 * If the ifile we're deleting is the currently open ifile, 131 * move off it. 132 */ 133 unmark(h); 134 if (h == curr_ifile) 135 curr_ifile = getoff_ifile(curr_ifile); 136 p = int_ifile(h); 137 unlink_ifile(p); 138 free(p->h_filename); 139 free(p); 140 } 141 142 /* 143 * Get the ifile after a given one in the list. 144 */ 145 IFILE 146 next_ifile(IFILE h) 147 { 148 struct ifile *p; 149 150 p = (h == NULL) ? &anchor : int_ifile(h); 151 if (p->h_next == &anchor) 152 return (NULL); 153 return (ext_ifile(p->h_next)); 154 } 155 156 /* 157 * Get the ifile before a given one in the list. 158 */ 159 IFILE 160 prev_ifile(IFILE h) 161 { 162 struct ifile *p; 163 164 p = (h == NULL) ? &anchor : int_ifile(h); 165 if (p->h_prev == &anchor) 166 return (NULL); 167 return (ext_ifile(p->h_prev)); 168 } 169 170 /* 171 * Return a different ifile from the given one. 172 */ 173 IFILE 174 getoff_ifile(IFILE ifile) 175 { 176 IFILE newifile; 177 178 if ((newifile = prev_ifile(ifile)) != NULL) 179 return (newifile); 180 if ((newifile = next_ifile(ifile)) != NULL) 181 return (newifile); 182 return (NULL); 183 } 184 185 /* 186 * Return the number of ifiles. 187 */ 188 int 189 nifile(void) 190 { 191 return (ifiles); 192 } 193 194 /* 195 * Find an ifile structure, given a filename. 196 */ 197 static struct ifile * 198 find_ifile(const char *filename) 199 { 200 struct ifile *p; 201 202 for (p = anchor.h_next; p != &anchor; p = p->h_next) 203 if (strcmp(filename, p->h_filename) == 0) 204 return (p); 205 return (NULL); 206 } 207 208 /* 209 * Get the ifile associated with a filename. 210 * If the filename has not been seen before, 211 * insert the new ifile after "prev" in the list. 212 */ 213 IFILE 214 get_ifile(char *filename, IFILE prev) 215 { 216 struct ifile *p; 217 218 if ((p = find_ifile(filename)) == NULL) 219 p = new_ifile(filename, int_ifile(prev)); 220 return (ext_ifile(p)); 221 } 222 223 /* 224 * Get the filename associated with a ifile. 225 */ 226 char * 227 get_filename(IFILE ifile) 228 { 229 if (ifile == NULL) 230 return (NULL); 231 return (int_ifile(ifile)->h_filename); 232 } 233 234 /* 235 * Get the index of the file associated with a ifile. 236 */ 237 int 238 get_index(IFILE ifile) 239 { 240 return (int_ifile(ifile)->h_index); 241 } 242 243 /* 244 * Save the file position to be associated with a given file. 245 */ 246 void 247 store_pos(IFILE ifile, struct scrpos *scrpos) 248 { 249 int_ifile(ifile)->h_scrpos = *scrpos; 250 } 251 252 /* 253 * Recall the file position associated with a file. 254 * If no position has been associated with the file, return -1. 255 */ 256 void 257 get_pos(IFILE ifile, struct scrpos *scrpos) 258 { 259 *scrpos = int_ifile(ifile)->h_scrpos; 260 } 261 262 /* 263 * Mark the ifile as "opened". 264 */ 265 void 266 set_open(IFILE ifile) 267 { 268 int_ifile(ifile)->h_opened = 1; 269 } 270 271 /* 272 * Return whether the ifile has been opened previously. 273 */ 274 int 275 opened(IFILE ifile) 276 { 277 return (int_ifile(ifile)->h_opened); 278 } 279 280 void 281 hold_ifile(IFILE ifile, int incr) 282 { 283 int_ifile(ifile)->h_hold += incr; 284 } 285 286 int 287 held_ifile(IFILE ifile) 288 { 289 return (int_ifile(ifile)->h_hold); 290 } 291 292 void * 293 get_filestate(IFILE ifile) 294 { 295 return (int_ifile(ifile)->h_filestate); 296 } 297 298 void 299 set_filestate(IFILE ifile, void *filestate) 300 { 301 int_ifile(ifile)->h_filestate = filestate; 302 } 303