1 1.5 simonb /* $NetBSD: ifile.c,v 1.5 2023/10/06 05:49:49 simonb Exp $ */ 2 1.1 tron 3 1.1 tron /* 4 1.5 simonb * Copyright (C) 1984-2023 Mark Nudelman 5 1.1 tron * 6 1.1 tron * You may distribute under the terms of either the GNU General Public 7 1.1 tron * License or the Less License, as specified in the README file. 8 1.1 tron * 9 1.4 tron * For more information, see the README file. 10 1.1 tron */ 11 1.1 tron 12 1.1 tron 13 1.1 tron /* 14 1.1 tron * An IFILE represents an input file. 15 1.1 tron * 16 1.1 tron * It is actually a pointer to an ifile structure, 17 1.1 tron * but is opaque outside this module. 18 1.1 tron * Ifile structures are kept in a linked list in the order they 19 1.1 tron * appear on the command line. 20 1.1 tron * Any new file which does not already appear in the list is 21 1.1 tron * inserted after the current file. 22 1.1 tron */ 23 1.1 tron 24 1.1 tron #include "less.h" 25 1.1 tron 26 1.5 simonb extern IFILE curr_ifile; 27 1.1 tron 28 1.1 tron struct ifile { 29 1.5 simonb struct ifile *h_next; /* Links for command line list */ 30 1.1 tron struct ifile *h_prev; 31 1.5 simonb char *h_filename; /* Name of the file */ 32 1.5 simonb char *h_rfilename; /* Canonical name of the file */ 33 1.5 simonb void *h_filestate; /* File state (used in ch.c) */ 34 1.5 simonb int h_index; /* Index within command line list */ 35 1.5 simonb int h_hold; /* Hold count */ 36 1.5 simonb char h_opened; /* Has this ifile been opened? */ 37 1.5 simonb struct scrpos h_scrpos; /* Saved position within the file */ 38 1.5 simonb void *h_altpipe; /* Alt pipe */ 39 1.5 simonb char *h_altfilename; /* Alt filename */ 40 1.1 tron }; 41 1.1 tron 42 1.1 tron /* 43 1.1 tron * Convert an IFILE (external representation) 44 1.1 tron * to a struct file (internal representation), and vice versa. 45 1.1 tron */ 46 1.5 simonb #define int_ifile(h) ((struct ifile *)(h)) 47 1.5 simonb #define ext_ifile(h) ((IFILE)(h)) 48 1.1 tron 49 1.1 tron /* 50 1.1 tron * Anchor for linked list. 51 1.1 tron */ 52 1.5 simonb static struct ifile anchor = { &anchor, &anchor, NULL, NULL, NULL, 0, 0, '\0', 53 1.1 tron { NULL_POSITION, 0 } }; 54 1.1 tron static int ifiles = 0; 55 1.1 tron 56 1.5 simonb static void incr_index(struct ifile *p, int incr) 57 1.1 tron { 58 1.1 tron for (; p != &anchor; p = p->h_next) 59 1.1 tron p->h_index += incr; 60 1.1 tron } 61 1.1 tron 62 1.1 tron /* 63 1.1 tron * Link an ifile into the ifile list. 64 1.1 tron */ 65 1.5 simonb static void link_ifile(struct ifile *p, struct ifile *prev) 66 1.1 tron { 67 1.1 tron /* 68 1.1 tron * Link into list. 69 1.1 tron */ 70 1.1 tron if (prev == NULL) 71 1.1 tron prev = &anchor; 72 1.1 tron p->h_next = prev->h_next; 73 1.1 tron p->h_prev = prev; 74 1.1 tron prev->h_next->h_prev = p; 75 1.1 tron prev->h_next = p; 76 1.1 tron /* 77 1.1 tron * Calculate index for the new one, 78 1.1 tron * and adjust the indexes for subsequent ifiles in the list. 79 1.1 tron */ 80 1.1 tron p->h_index = prev->h_index + 1; 81 1.1 tron incr_index(p->h_next, 1); 82 1.1 tron ifiles++; 83 1.1 tron } 84 1.1 tron 85 1.1 tron /* 86 1.1 tron * Unlink an ifile from the ifile list. 87 1.1 tron */ 88 1.5 simonb static void unlink_ifile(struct ifile *p) 89 1.1 tron { 90 1.1 tron p->h_next->h_prev = p->h_prev; 91 1.1 tron p->h_prev->h_next = p->h_next; 92 1.1 tron incr_index(p->h_next, -1); 93 1.1 tron ifiles--; 94 1.1 tron } 95 1.1 tron 96 1.1 tron /* 97 1.1 tron * Allocate a new ifile structure and stick a filename in it. 98 1.1 tron * It should go after "prev" in the list 99 1.1 tron * (or at the beginning of the list if "prev" is NULL). 100 1.1 tron * Return a pointer to the new ifile structure. 101 1.1 tron */ 102 1.5 simonb static struct ifile * new_ifile(char *filename, struct ifile *prev) 103 1.1 tron { 104 1.5 simonb struct ifile *p; 105 1.1 tron 106 1.1 tron /* 107 1.1 tron * Allocate and initialize structure. 108 1.1 tron */ 109 1.1 tron p = (struct ifile *) ecalloc(1, sizeof(struct ifile)); 110 1.1 tron p->h_filename = save(filename); 111 1.5 simonb p->h_rfilename = lrealpath(filename); 112 1.1 tron p->h_scrpos.pos = NULL_POSITION; 113 1.1 tron p->h_opened = 0; 114 1.1 tron p->h_hold = 0; 115 1.1 tron p->h_filestate = NULL; 116 1.5 simonb p->h_altfilename = NULL; 117 1.5 simonb p->h_altpipe = NULL; 118 1.1 tron link_ifile(p, prev); 119 1.5 simonb /* 120 1.5 simonb * {{ It's dodgy to call mark.c functions from here; 121 1.5 simonb * there is potentially dangerous recursion. 122 1.5 simonb * Probably need to revisit this design. }} 123 1.5 simonb */ 124 1.5 simonb mark_check_ifile(ext_ifile(p)); 125 1.1 tron return (p); 126 1.1 tron } 127 1.1 tron 128 1.1 tron /* 129 1.1 tron * Delete an existing ifile structure. 130 1.1 tron */ 131 1.5 simonb public void del_ifile(IFILE h) 132 1.1 tron { 133 1.5 simonb struct ifile *p; 134 1.1 tron 135 1.1 tron if (h == NULL_IFILE) 136 1.1 tron return; 137 1.1 tron /* 138 1.1 tron * If the ifile we're deleting is the currently open ifile, 139 1.1 tron * move off it. 140 1.1 tron */ 141 1.1 tron unmark(h); 142 1.1 tron if (h == curr_ifile) 143 1.1 tron curr_ifile = getoff_ifile(curr_ifile); 144 1.1 tron p = int_ifile(h); 145 1.1 tron unlink_ifile(p); 146 1.5 simonb free(p->h_rfilename); 147 1.1 tron free(p->h_filename); 148 1.1 tron free(p); 149 1.1 tron } 150 1.1 tron 151 1.1 tron /* 152 1.1 tron * Get the ifile after a given one in the list. 153 1.1 tron */ 154 1.5 simonb public IFILE next_ifile(IFILE h) 155 1.1 tron { 156 1.5 simonb struct ifile *p; 157 1.1 tron 158 1.1 tron p = (h == NULL_IFILE) ? &anchor : int_ifile(h); 159 1.1 tron if (p->h_next == &anchor) 160 1.1 tron return (NULL_IFILE); 161 1.1 tron return (ext_ifile(p->h_next)); 162 1.1 tron } 163 1.1 tron 164 1.1 tron /* 165 1.1 tron * Get the ifile before a given one in the list. 166 1.1 tron */ 167 1.5 simonb public IFILE prev_ifile(IFILE h) 168 1.1 tron { 169 1.5 simonb struct ifile *p; 170 1.1 tron 171 1.1 tron p = (h == NULL_IFILE) ? &anchor : int_ifile(h); 172 1.1 tron if (p->h_prev == &anchor) 173 1.1 tron return (NULL_IFILE); 174 1.1 tron return (ext_ifile(p->h_prev)); 175 1.1 tron } 176 1.1 tron 177 1.1 tron /* 178 1.1 tron * Return a different ifile from the given one. 179 1.1 tron */ 180 1.5 simonb public IFILE getoff_ifile(IFILE ifile) 181 1.1 tron { 182 1.1 tron IFILE newifile; 183 1.1 tron 184 1.1 tron if ((newifile = prev_ifile(ifile)) != NULL_IFILE) 185 1.1 tron return (newifile); 186 1.1 tron if ((newifile = next_ifile(ifile)) != NULL_IFILE) 187 1.1 tron return (newifile); 188 1.1 tron return (NULL_IFILE); 189 1.1 tron } 190 1.1 tron 191 1.1 tron /* 192 1.1 tron * Return the number of ifiles. 193 1.1 tron */ 194 1.5 simonb public int nifile(void) 195 1.1 tron { 196 1.1 tron return (ifiles); 197 1.1 tron } 198 1.1 tron 199 1.1 tron /* 200 1.1 tron * Find an ifile structure, given a filename. 201 1.1 tron */ 202 1.5 simonb static struct ifile * find_ifile(char *filename) 203 1.1 tron { 204 1.5 simonb struct ifile *p; 205 1.5 simonb char *rfilename = lrealpath(filename); 206 1.1 tron 207 1.1 tron for (p = anchor.h_next; p != &anchor; p = p->h_next) 208 1.5 simonb { 209 1.5 simonb if (strcmp(rfilename, p->h_rfilename) == 0) 210 1.5 simonb { 211 1.5 simonb /* 212 1.5 simonb * If given name is shorter than the name we were 213 1.5 simonb * previously using for this file, adopt shorter name. 214 1.5 simonb */ 215 1.5 simonb if (strlen(filename) < strlen(p->h_filename)) 216 1.5 simonb { 217 1.5 simonb free(p->h_filename); 218 1.5 simonb p->h_filename = save(filename); 219 1.5 simonb } 220 1.5 simonb break; 221 1.5 simonb } 222 1.5 simonb } 223 1.5 simonb free(rfilename); 224 1.5 simonb if (p == &anchor) 225 1.5 simonb p = NULL; 226 1.5 simonb return (p); 227 1.1 tron } 228 1.1 tron 229 1.1 tron /* 230 1.1 tron * Get the ifile associated with a filename. 231 1.1 tron * If the filename has not been seen before, 232 1.1 tron * insert the new ifile after "prev" in the list. 233 1.1 tron */ 234 1.5 simonb public IFILE get_ifile(char *filename, IFILE prev) 235 1.1 tron { 236 1.5 simonb struct ifile *p; 237 1.1 tron 238 1.1 tron if ((p = find_ifile(filename)) == NULL) 239 1.1 tron p = new_ifile(filename, int_ifile(prev)); 240 1.1 tron return (ext_ifile(p)); 241 1.1 tron } 242 1.1 tron 243 1.1 tron /* 244 1.5 simonb * Get the display filename associated with a ifile. 245 1.1 tron */ 246 1.5 simonb public char * get_filename(IFILE ifile) 247 1.1 tron { 248 1.1 tron if (ifile == NULL) 249 1.1 tron return (NULL); 250 1.1 tron return (int_ifile(ifile)->h_filename); 251 1.1 tron } 252 1.1 tron 253 1.1 tron /* 254 1.5 simonb * Get the canonical filename associated with a ifile. 255 1.5 simonb */ 256 1.5 simonb public char * get_real_filename(IFILE ifile) 257 1.5 simonb { 258 1.5 simonb if (ifile == NULL) 259 1.5 simonb return (NULL); 260 1.5 simonb return (int_ifile(ifile)->h_rfilename); 261 1.5 simonb } 262 1.5 simonb 263 1.5 simonb /* 264 1.1 tron * Get the index of the file associated with a ifile. 265 1.1 tron */ 266 1.5 simonb public int get_index(IFILE ifile) 267 1.1 tron { 268 1.1 tron return (int_ifile(ifile)->h_index); 269 1.1 tron } 270 1.1 tron 271 1.1 tron /* 272 1.1 tron * Save the file position to be associated with a given file. 273 1.1 tron */ 274 1.5 simonb public void store_pos(IFILE ifile, struct scrpos *scrpos) 275 1.1 tron { 276 1.1 tron int_ifile(ifile)->h_scrpos = *scrpos; 277 1.1 tron } 278 1.1 tron 279 1.1 tron /* 280 1.1 tron * Recall the file position associated with a file. 281 1.1 tron * If no position has been associated with the file, return NULL_POSITION. 282 1.1 tron */ 283 1.5 simonb public void get_pos(IFILE ifile, struct scrpos *scrpos) 284 1.1 tron { 285 1.1 tron *scrpos = int_ifile(ifile)->h_scrpos; 286 1.1 tron } 287 1.1 tron 288 1.1 tron /* 289 1.1 tron * Mark the ifile as "opened". 290 1.1 tron */ 291 1.5 simonb public void set_open(IFILE ifile) 292 1.1 tron { 293 1.1 tron int_ifile(ifile)->h_opened = 1; 294 1.1 tron } 295 1.1 tron 296 1.1 tron /* 297 1.1 tron * Return whether the ifile has been opened previously. 298 1.1 tron */ 299 1.5 simonb public int opened(IFILE ifile) 300 1.1 tron { 301 1.1 tron return (int_ifile(ifile)->h_opened); 302 1.1 tron } 303 1.1 tron 304 1.5 simonb public void hold_ifile(IFILE ifile, int incr) 305 1.1 tron { 306 1.1 tron int_ifile(ifile)->h_hold += incr; 307 1.1 tron } 308 1.1 tron 309 1.5 simonb public int held_ifile(IFILE ifile) 310 1.1 tron { 311 1.1 tron return (int_ifile(ifile)->h_hold); 312 1.1 tron } 313 1.1 tron 314 1.5 simonb public void * get_filestate(IFILE ifile) 315 1.1 tron { 316 1.1 tron return (int_ifile(ifile)->h_filestate); 317 1.1 tron } 318 1.1 tron 319 1.5 simonb public void set_filestate(IFILE ifile, void *filestate) 320 1.1 tron { 321 1.1 tron int_ifile(ifile)->h_filestate = filestate; 322 1.1 tron } 323 1.1 tron 324 1.5 simonb public void set_altpipe(IFILE ifile, void *p) 325 1.5 simonb { 326 1.5 simonb int_ifile(ifile)->h_altpipe = p; 327 1.5 simonb } 328 1.5 simonb 329 1.5 simonb public void *get_altpipe(IFILE ifile) 330 1.5 simonb { 331 1.5 simonb return (int_ifile(ifile)->h_altpipe); 332 1.5 simonb } 333 1.5 simonb 334 1.5 simonb public void set_altfilename(IFILE ifile, char *altfilename) 335 1.5 simonb { 336 1.5 simonb struct ifile *p = int_ifile(ifile); 337 1.5 simonb if (p->h_altfilename != NULL && p->h_altfilename != altfilename) 338 1.5 simonb free(p->h_altfilename); 339 1.5 simonb p->h_altfilename = altfilename; 340 1.5 simonb } 341 1.5 simonb 342 1.5 simonb public char * get_altfilename(IFILE ifile) 343 1.5 simonb { 344 1.5 simonb return (int_ifile(ifile)->h_altfilename); 345 1.5 simonb } 346 1.5 simonb 347 1.1 tron #if 0 348 1.5 simonb public void if_dump(void) 349 1.1 tron { 350 1.5 simonb struct ifile *p; 351 1.1 tron 352 1.1 tron for (p = anchor.h_next; p != &anchor; p = p->h_next) 353 1.1 tron { 354 1.1 tron printf("%x: %d. <%s> pos %d,%x\n", 355 1.1 tron p, p->h_index, p->h_filename, 356 1.1 tron p->h_scrpos.ln, p->h_scrpos.pos); 357 1.1 tron ch_dump(p->h_filestate); 358 1.1 tron } 359 1.1 tron } 360 1.1 tron #endif 361