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 }