(root)/
man-db-2.12.0/
lib/
compression.c
       1  /*
       2   * compression.c: code to find decompressor / compression extension
       3   *
       4   * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.)
       5   * Copyright (C) 2001-2022 Colin Watson.
       6   *
       7   * This file is part of man-db.
       8   *
       9   * man-db is free software; you can redistribute it and/or modify it
      10   * under the terms of the GNU General Public License as published by
      11   * the Free Software Foundation; either version 2 of the License, or
      12   * (at your option) any later version.
      13   *
      14   * man-db is distributed in the hope that it will be useful, but
      15   * WITHOUT ANY WARRANTY; without even the implied warranty of
      16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17   * GNU General Public License for more details.
      18   *
      19   * You should have received a copy of the GNU General Public License
      20   * along with man-db; if not, write to the Free Software Foundation,
      21   * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      22   *
      23   * Sat Aug 20 15:01:02 BST 1994  Wilf. (G.Wilford@ee.surrey.ac.uk)
      24   */
      25  
      26  #ifdef HAVE_CONFIG_H
      27  #  include "config.h"
      28  #endif /* HAVE_CONFIG_H */
      29  
      30  #include <assert.h>
      31  #include <stdbool.h>
      32  #include <stdio.h>
      33  #include <errno.h>
      34  #include <signal.h>
      35  #include <string.h>
      36  #include <stdlib.h>
      37  #include <unistd.h>
      38  #include <sys/types.h>
      39  #include <sys/stat.h>
      40  #include <fcntl.h>
      41  
      42  #include "error.h"
      43  #include "xstrndup.h"
      44  #include "xvasprintf.h"
      45  
      46  #include "manconfig.h"
      47  
      48  #include "appendstr.h"
      49  #include "compression.h"
      50  
      51  /*--------------------------------------------------------------------------*/
      52  /* This is where we define the decompressors used to decompress any nroff   */
      53  /* source that we find. All cat pages are compressed with either gzip (if   */
      54  /* available) or compress. This is not the place to define _the_ cat page   */
      55  /* decompressor - see ./manconfig.h for that.                               */
      56  /*                                                                          */
      57  /* To add a decompressor all you need to know is its name (preferably its   */
      58  /* location), and the unique extension that it gives to files compressed    */
      59  /* with it. Here is an example. You have a compressor named foobar and      */
      60  /* compressed files have an extension of .fb . It is located in /usr/bin    */
      61  /* and requires a -d option to be used as a decompressor. Add the following */
      62  /* line to the structure below.                                             */
      63  /*                                                                          */
      64  /* {"/usr/bin/foobar -d", "fb", NULL},                                      */
      65  /*--------------------------------------------------------------------------*/
      66  
      67  struct compression comp_list[] = {
      68  
      69  /* If we have gzip, incorporate the following */
      70  #ifdef HAVE_GZIP
      71  	{PROG_GUNZIP, "gz", NULL},
      72  	{PROG_GUNZIP, "z", NULL},
      73  #endif /* HAVE_GZIP */
      74  
      75  /* If we have compress, incorporate the following */
      76  #ifdef HAVE_COMPRESS
      77  	{PROG_UNCOMPRESS, "Z", NULL},
      78  /* Else if we have gzip, incorporate the following */
      79  #elif defined (HAVE_GZIP)
      80  	{PROG_GUNZIP, "Z", NULL},
      81  #endif /* HAVE_COMPRESS || HAVE_GZIP */
      82  
      83  /* If we have bzip2, incorporate the following */
      84  #ifdef HAVE_BZIP2
      85  	{PROG_BUNZIP2, "bz2", NULL},
      86  #endif /* HAVE_BZIP2 */
      87  
      88  /* If we have xz, incorporate the following */
      89  #ifdef HAVE_XZ
      90  	{PROG_UNXZ, "xz", NULL},
      91  	{PROG_UNXZ, "lzma", NULL},
      92  /* Else if we have lzma, incorporate the following */
      93  #elif defined (HAVE_LZMA)
      94  	{PROG_UNLZMA, "lzma", NULL},
      95  #endif /* HAVE_XZ || HAVE_LZMA */
      96  
      97  /* If we have lzip, incorporate the following */
      98  #ifdef HAVE_LZIP
      99  	{PROG_UNLZIP, "lz", NULL},
     100  #endif /* HAVE_LZIP */
     101  
     102  /* If we have zstd, incorporate the following */
     103  #ifdef HAVE_ZSTD
     104  	{PROG_UNZSTD, "zst", NULL},
     105  	{PROG_UNZSTD, "zstd", NULL},
     106  #endif /* HAVE_ZSTD */
     107  
     108  /*------------------------------------------------------*/
     109  /* Add your decompressor(s) and extension(s) below here */
     110  /*------------------------------------------------------*/
     111  
     112  /*----------------*/
     113  /* and above here */
     114  /*----------------*/
     115  
     116  /* ... and the last structure is */
     117  	{NULL, NULL, NULL}
     118  };
     119  
     120  /* Take filename as arg, return structure containing decompressor
     121     and extension, or NULL if no comp extension found.
     122     If want_stem, set comp->stem to the filename without extension, which
     123     the caller should free.
     124  
     125     eg.
     126     	filename = /usr/man/man1/foo.1.gz
     127  
     128  	comp->prog = "/usr/bin/gzip -dc";
     129     	comp->ext = "gz";
     130     	comp->stem = "/usr/man/man1/foo.1";
     131   */
     132  struct compression *comp_info (const char *filename, bool want_stem)
     133  {
     134  	const char *ext;
     135  	static struct compression hpux_comp =
     136  		{PROG_GUNZIP " -S \"\"", "", NULL};
     137  
     138  	ext = strrchr (filename, '.');
     139  
     140  	if (ext) {
     141  		struct compression *comp;
     142  		for (comp = comp_list; comp->ext; comp++) {
     143  			if (strcmp (comp->ext, ext + 1) == 0) {
     144  				if (want_stem)
     145  					comp->stem = xstrndup (filename,
     146  							       ext - filename);
     147  				else
     148  					comp->stem = NULL;
     149  				return comp;
     150  			}
     151  		}
     152  	}
     153  
     154  	if (*PROG_GUNZIP) {
     155  		ext = strstr (filename, ".Z/");
     156  		if (ext) {
     157  			if (want_stem)
     158  				hpux_comp.stem = xstrndup (filename,
     159  							   ext - filename);
     160  			else
     161  				hpux_comp.stem = NULL;
     162  			return &hpux_comp;
     163  		}
     164  	}
     165  
     166  	return NULL;
     167  }
     168  
     169  /* take filename w/o comp ext. as arg, return comp->stem as a relative
     170     compressed file or NULL if none found */
     171  struct compression *comp_file (const char *filename)
     172  {
     173  	size_t len;
     174  	char *compfile;
     175  	struct compression *comp;
     176  
     177  	compfile = xasprintf ("%s.", filename);
     178  	assert (compfile);
     179  	len = strlen (compfile);
     180  
     181  	for (comp = comp_list; comp->ext; comp++) {
     182  		struct stat buf;
     183  
     184  		compfile = appendstr (compfile, comp->ext, (void *) 0);
     185  
     186  		if (stat (compfile, &buf) == 0) {
     187  			comp->stem = compfile;
     188  			return comp;
     189  		}
     190  
     191  		*(compfile + len) = '\0';
     192  	}
     193  	free (compfile);
     194  	return NULL;
     195  }