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