1238730Sdelphij/* 2369759Sgit2svn * Copyright (C) 1984-2021 Mark Nudelman 3238730Sdelphij * 4238730Sdelphij * You may distribute under the terms of either the GNU General Public 5238730Sdelphij * License or the Less License, as specified in the README file. 6238730Sdelphij * 7238730Sdelphij * For more information, see the README file. 8238730Sdelphij */ 960786Sps 1060786Sps 1160786Sps/* 1260786Sps * An IFILE represents an input file. 1360786Sps * 1460786Sps * It is actually a pointer to an ifile structure, 1560786Sps * but is opaque outside this module. 1660786Sps * Ifile structures are kept in a linked list in the order they 1760786Sps * appear on the command line. 1860786Sps * Any new file which does not already appear in the list is 1960786Sps * inserted after the current file. 2060786Sps */ 2160786Sps 2260786Sps#include "less.h" 2360786Sps 24369759Sgit2svnextern IFILE curr_ifile; 2560786Sps 2660786Spsstruct ifile { 27330570Sdelphij struct ifile *h_next; /* Links for command line list */ 2860786Sps struct ifile *h_prev; 29330570Sdelphij char *h_filename; /* Name of the file */ 30369759Sgit2svn char *h_rfilename; /* Canonical name of the file */ 31330570Sdelphij void *h_filestate; /* File state (used in ch.c) */ 32330570Sdelphij int h_index; /* Index within command line list */ 33330570Sdelphij int h_hold; /* Hold count */ 34330570Sdelphij char h_opened; /* Has this ifile been opened? */ 35330570Sdelphij struct scrpos h_scrpos; /* Saved position within the file */ 36330570Sdelphij void *h_altpipe; /* Alt pipe */ 37330570Sdelphij char *h_altfilename; /* Alt filename */ 3860786Sps}; 3960786Sps 4060786Sps/* 4160786Sps * Convert an IFILE (external representation) 4260786Sps * to a struct file (internal representation), and vice versa. 4360786Sps */ 44369759Sgit2svn#define int_ifile(h) ((struct ifile *)(h)) 45369759Sgit2svn#define ext_ifile(h) ((IFILE)(h)) 4660786Sps 4760786Sps/* 4860786Sps * Anchor for linked list. 4960786Sps */ 50369759Sgit2svnstatic struct ifile anchor = { &anchor, &anchor, NULL, NULL, NULL, 0, 0, '\0', 5160786Sps { NULL_POSITION, 0 } }; 5260786Spsstatic int ifiles = 0; 5360786Sps 5460786Sps static void 5560786Spsincr_index(p, incr) 56330570Sdelphij struct ifile *p; 5760786Sps int incr; 5860786Sps{ 5960786Sps for (; p != &anchor; p = p->h_next) 6060786Sps p->h_index += incr; 6160786Sps} 6260786Sps 6360786Sps/* 6460786Sps * Link an ifile into the ifile list. 6560786Sps */ 6660786Sps static void 6760786Spslink_ifile(p, prev) 6860786Sps struct ifile *p; 6960786Sps struct ifile *prev; 7060786Sps{ 7160786Sps /* 7260786Sps * Link into list. 7360786Sps */ 7460786Sps if (prev == NULL) 7560786Sps prev = &anchor; 7660786Sps p->h_next = prev->h_next; 7760786Sps p->h_prev = prev; 7860786Sps prev->h_next->h_prev = p; 7960786Sps prev->h_next = p; 8060786Sps /* 8160786Sps * Calculate index for the new one, 8260786Sps * and adjust the indexes for subsequent ifiles in the list. 8360786Sps */ 8460786Sps p->h_index = prev->h_index + 1; 8560786Sps incr_index(p->h_next, 1); 8660786Sps ifiles++; 8760786Sps} 8860786Sps 8960786Sps/* 9060786Sps * Unlink an ifile from the ifile list. 9160786Sps */ 9260786Sps static void 9360786Spsunlink_ifile(p) 9460786Sps struct ifile *p; 9560786Sps{ 9660786Sps p->h_next->h_prev = p->h_prev; 9760786Sps p->h_prev->h_next = p->h_next; 9860786Sps incr_index(p->h_next, -1); 9960786Sps ifiles--; 10060786Sps} 10160786Sps 10260786Sps/* 10360786Sps * Allocate a new ifile structure and stick a filename in it. 10460786Sps * It should go after "prev" in the list 10560786Sps * (or at the beginning of the list if "prev" is NULL). 10660786Sps * Return a pointer to the new ifile structure. 10760786Sps */ 10860786Sps static struct ifile * 10960786Spsnew_ifile(filename, prev) 11060786Sps char *filename; 11160786Sps struct ifile *prev; 11260786Sps{ 113330570Sdelphij struct ifile *p; 11460786Sps 11560786Sps /* 11660786Sps * Allocate and initialize structure. 11760786Sps */ 11860786Sps p = (struct ifile *) ecalloc(1, sizeof(struct ifile)); 11960786Sps p->h_filename = save(filename); 120369759Sgit2svn p->h_rfilename = lrealpath(filename); 12160786Sps p->h_scrpos.pos = NULL_POSITION; 12260786Sps p->h_opened = 0; 12360786Sps p->h_hold = 0; 12460786Sps p->h_filestate = NULL; 125369759Sgit2svn p->h_altfilename = NULL; 126369759Sgit2svn p->h_altpipe = NULL; 12760786Sps link_ifile(p, prev); 128355504Sdelphij /* 129355504Sdelphij * {{ It's dodgy to call mark.c functions from here; 130355504Sdelphij * there is potentially dangerous recursion. 131355504Sdelphij * Probably need to revisit this design. }} 132355504Sdelphij */ 133355504Sdelphij mark_check_ifile(ext_ifile(p)); 13460786Sps return (p); 13560786Sps} 13660786Sps 13760786Sps/* 13860786Sps * Delete an existing ifile structure. 13960786Sps */ 14060786Sps public void 14160786Spsdel_ifile(h) 14260786Sps IFILE h; 14360786Sps{ 144330570Sdelphij struct ifile *p; 14560786Sps 14660786Sps if (h == NULL_IFILE) 14760786Sps return; 14860786Sps /* 14960786Sps * If the ifile we're deleting is the currently open ifile, 15060786Sps * move off it. 15160786Sps */ 15260786Sps unmark(h); 15360786Sps if (h == curr_ifile) 15460786Sps curr_ifile = getoff_ifile(curr_ifile); 15560786Sps p = int_ifile(h); 15660786Sps unlink_ifile(p); 157369759Sgit2svn free(p->h_rfilename); 15860786Sps free(p->h_filename); 15960786Sps free(p); 16060786Sps} 16160786Sps 16260786Sps/* 16360786Sps * Get the ifile after a given one in the list. 16460786Sps */ 16560786Sps public IFILE 16660786Spsnext_ifile(h) 16760786Sps IFILE h; 16860786Sps{ 169330570Sdelphij struct ifile *p; 17060786Sps 17160786Sps p = (h == NULL_IFILE) ? &anchor : int_ifile(h); 17260786Sps if (p->h_next == &anchor) 17360786Sps return (NULL_IFILE); 17460786Sps return (ext_ifile(p->h_next)); 17560786Sps} 17660786Sps 17760786Sps/* 17860786Sps * Get the ifile before a given one in the list. 17960786Sps */ 18060786Sps public IFILE 18160786Spsprev_ifile(h) 18260786Sps IFILE h; 18360786Sps{ 184330570Sdelphij struct ifile *p; 18560786Sps 18660786Sps p = (h == NULL_IFILE) ? &anchor : int_ifile(h); 18760786Sps if (p->h_prev == &anchor) 18860786Sps return (NULL_IFILE); 18960786Sps return (ext_ifile(p->h_prev)); 19060786Sps} 19160786Sps 19260786Sps/* 19360786Sps * Return a different ifile from the given one. 19460786Sps */ 19560786Sps public IFILE 19660786Spsgetoff_ifile(ifile) 19760786Sps IFILE ifile; 19860786Sps{ 19960786Sps IFILE newifile; 20060786Sps 20160786Sps if ((newifile = prev_ifile(ifile)) != NULL_IFILE) 20260786Sps return (newifile); 20360786Sps if ((newifile = next_ifile(ifile)) != NULL_IFILE) 20460786Sps return (newifile); 20560786Sps return (NULL_IFILE); 20660786Sps} 20760786Sps 20860786Sps/* 20960786Sps * Return the number of ifiles. 21060786Sps */ 21160786Sps public int 212355504Sdelphijnifile(VOID_PARAM) 21360786Sps{ 21460786Sps return (ifiles); 21560786Sps} 21660786Sps 21760786Sps/* 21860786Sps * Find an ifile structure, given a filename. 21960786Sps */ 22060786Sps static struct ifile * 22160786Spsfind_ifile(filename) 22260786Sps char *filename; 22360786Sps{ 224330570Sdelphij struct ifile *p; 225355504Sdelphij char *rfilename = lrealpath(filename); 22660786Sps 22760786Sps for (p = anchor.h_next; p != &anchor; p = p->h_next) 228355504Sdelphij { 229369759Sgit2svn if (strcmp(rfilename, p->h_rfilename) == 0) 230355504Sdelphij { 231355504Sdelphij /* 232355504Sdelphij * If given name is shorter than the name we were 233355504Sdelphij * previously using for this file, adopt shorter name. 234355504Sdelphij */ 235355504Sdelphij if (strlen(filename) < strlen(p->h_filename)) 236369759Sgit2svn { 237369759Sgit2svn free(p->h_filename); 238369759Sgit2svn p->h_filename = save(filename); 239369759Sgit2svn } 240355504Sdelphij break; 241355504Sdelphij } 242355504Sdelphij } 243355504Sdelphij free(rfilename); 244355504Sdelphij if (p == &anchor) 245355504Sdelphij p = NULL; 246355504Sdelphij return (p); 24760786Sps} 24860786Sps 24960786Sps/* 25060786Sps * Get the ifile associated with a filename. 25160786Sps * If the filename has not been seen before, 25260786Sps * insert the new ifile after "prev" in the list. 25360786Sps */ 25460786Sps public IFILE 25560786Spsget_ifile(filename, prev) 25660786Sps char *filename; 25760786Sps IFILE prev; 25860786Sps{ 259330570Sdelphij struct ifile *p; 26060786Sps 26160786Sps if ((p = find_ifile(filename)) == NULL) 26260786Sps p = new_ifile(filename, int_ifile(prev)); 26360786Sps return (ext_ifile(p)); 26460786Sps} 26560786Sps 26660786Sps/* 267369759Sgit2svn * Get the display filename associated with a ifile. 26860786Sps */ 26960786Sps public char * 27060786Spsget_filename(ifile) 27160786Sps IFILE ifile; 27260786Sps{ 27360786Sps if (ifile == NULL) 27460786Sps return (NULL); 27560786Sps return (int_ifile(ifile)->h_filename); 27660786Sps} 27760786Sps 27860786Sps/* 279369759Sgit2svn * Get the canonical filename associated with a ifile. 280369759Sgit2svn */ 281369759Sgit2svn public char * 282369759Sgit2svnget_real_filename(ifile) 283369759Sgit2svn IFILE ifile; 284369759Sgit2svn{ 285369759Sgit2svn if (ifile == NULL) 286369759Sgit2svn return (NULL); 287369759Sgit2svn return (int_ifile(ifile)->h_rfilename); 288369759Sgit2svn} 289369759Sgit2svn 290369759Sgit2svn/* 29160786Sps * Get the index of the file associated with a ifile. 29260786Sps */ 29360786Sps public int 29460786Spsget_index(ifile) 29560786Sps IFILE ifile; 29660786Sps{ 29760786Sps return (int_ifile(ifile)->h_index); 29860786Sps} 29960786Sps 30060786Sps/* 30160786Sps * Save the file position to be associated with a given file. 30260786Sps */ 30360786Sps public void 30460786Spsstore_pos(ifile, scrpos) 30560786Sps IFILE ifile; 30660786Sps struct scrpos *scrpos; 30760786Sps{ 30860786Sps int_ifile(ifile)->h_scrpos = *scrpos; 30960786Sps} 31060786Sps 31160786Sps/* 31260786Sps * Recall the file position associated with a file. 31360786Sps * If no position has been associated with the file, return NULL_POSITION. 31460786Sps */ 31560786Sps public void 31660786Spsget_pos(ifile, scrpos) 31760786Sps IFILE ifile; 31860786Sps struct scrpos *scrpos; 31960786Sps{ 32060786Sps *scrpos = int_ifile(ifile)->h_scrpos; 32160786Sps} 32260786Sps 32360786Sps/* 32460786Sps * Mark the ifile as "opened". 32560786Sps */ 32660786Sps public void 32760786Spsset_open(ifile) 32860786Sps IFILE ifile; 32960786Sps{ 33060786Sps int_ifile(ifile)->h_opened = 1; 33160786Sps} 33260786Sps 33360786Sps/* 33460786Sps * Return whether the ifile has been opened previously. 33560786Sps */ 33660786Sps public int 33760786Spsopened(ifile) 33860786Sps IFILE ifile; 33960786Sps{ 34060786Sps return (int_ifile(ifile)->h_opened); 34160786Sps} 34260786Sps 34360786Sps public void 34460786Spshold_ifile(ifile, incr) 34560786Sps IFILE ifile; 34660786Sps int incr; 34760786Sps{ 34860786Sps int_ifile(ifile)->h_hold += incr; 34960786Sps} 35060786Sps 35160786Sps public int 35260786Spsheld_ifile(ifile) 35360786Sps IFILE ifile; 35460786Sps{ 35560786Sps return (int_ifile(ifile)->h_hold); 35660786Sps} 35760786Sps 35860786Sps public void * 35960786Spsget_filestate(ifile) 36060786Sps IFILE ifile; 36160786Sps{ 36260786Sps return (int_ifile(ifile)->h_filestate); 36360786Sps} 36460786Sps 36560786Sps public void 36660786Spsset_filestate(ifile, filestate) 36760786Sps IFILE ifile; 36860786Sps void *filestate; 36960786Sps{ 37060786Sps int_ifile(ifile)->h_filestate = filestate; 37160786Sps} 37260786Sps 373330570Sdelphij public void 374330570Sdelphijset_altpipe(ifile, p) 375330570Sdelphij IFILE ifile; 376330570Sdelphij void *p; 377330570Sdelphij{ 378330570Sdelphij int_ifile(ifile)->h_altpipe = p; 379330570Sdelphij} 380330570Sdelphij 381330570Sdelphij public void * 382330570Sdelphijget_altpipe(ifile) 383330570Sdelphij IFILE ifile; 384330570Sdelphij{ 385330570Sdelphij return (int_ifile(ifile)->h_altpipe); 386330570Sdelphij} 387330570Sdelphij 388330570Sdelphij public void 389330570Sdelphijset_altfilename(ifile, altfilename) 390330570Sdelphij IFILE ifile; 391330570Sdelphij char *altfilename; 392330570Sdelphij{ 393330570Sdelphij struct ifile *p = int_ifile(ifile); 394369759Sgit2svn if (p->h_altfilename != NULL && p->h_altfilename != altfilename) 395330570Sdelphij free(p->h_altfilename); 396330570Sdelphij p->h_altfilename = altfilename; 397330570Sdelphij} 398330570Sdelphij 399330570Sdelphij public char * 400330570Sdelphijget_altfilename(ifile) 401330570Sdelphij IFILE ifile; 402330570Sdelphij{ 403330570Sdelphij return (int_ifile(ifile)->h_altfilename); 404330570Sdelphij} 405330570Sdelphij 40660786Sps#if 0 40760786Sps public void 408355504Sdelphijif_dump(VOID_PARAM) 40960786Sps{ 410330570Sdelphij struct ifile *p; 41160786Sps 41260786Sps for (p = anchor.h_next; p != &anchor; p = p->h_next) 41360786Sps { 41460786Sps printf("%x: %d. <%s> pos %d,%x\n", 41560786Sps p, p->h_index, p->h_filename, 41660786Sps p->h_scrpos.ln, p->h_scrpos.pos); 41760786Sps ch_dump(p->h_filestate); 41860786Sps } 41960786Sps} 42060786Sps#endif 421