]> git.draconx.ca Git - liblbx.git/blob - src/lbxtool.c
Implement filename globbing on list/extract.
[liblbx.git] / src / lbxtool.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <getopt.h>
6 #include <fnmatch.h>
7
8 #include "lbx.h"
9
10 static const char *progname;
11 #define errmsg(fmt, ...) (\
12         fprintf(stderr, "%s: " fmt, progname, __VA_ARGS__)\
13 )
14
15 enum {
16         MODE_NONE,
17         MODE_LIST,
18         MODE_EXTRACT,
19 };
20
21 int filematch(char **argv, const char *name)
22 {
23         int rc, i;
24
25         for (i = 0; argv[i]; i++) {
26                 switch(fnmatch(argv[i], name, 0)) {
27                 case 0:
28                         return 0;
29                 case FNM_NOMATCH:
30                         break;
31                 default:
32                         errmsg("error matching glob: %s.\n", argv[i]);
33                         return 1;
34                 }
35         }
36
37         return i ? -1: 0;
38 }
39
40 int list(FILE *f, const char *name, int verbose, char **argv) {
41         LBX *lbx;
42         size_t nfiles;
43         unsigned int i;
44
45         lbx = lbx_fopen(f, name);
46         if (!lbx) {
47                 errmsg("failed to open archive: %s.\n", lbx_strerror());
48                 return EXIT_FAILURE;
49         }
50
51         nfiles = lbx_numfiles(lbx);
52         if (verbose) {
53                 printf("Files in archive: %zu\n", nfiles);
54         }
55
56         for (i = 0; i < nfiles; i++) {
57                 struct lbx_statbuf stat;
58
59                 lbx_stat(lbx, i, &stat);
60
61                 switch (filematch(argv, stat.name)) {
62                 case -1: continue;
63                 case  0: break;
64                 default: goto err;
65                 }
66
67                 printf("%s", stat.name);
68                 if (verbose) {
69                         printf(" size=%zu bytes", stat.size);
70                 }
71
72                 putchar('\n');
73         }
74
75         lbx_close(lbx);
76         return EXIT_SUCCESS;
77 err:
78         lbx_close(lbx);
79         return EXIT_FAILURE;
80 }
81
82 int extract(FILE *f, const char *name, int verbose, char **argv) {
83         LBX *lbx;
84         size_t nfiles;
85         unsigned int i;
86
87         lbx = lbx_fopen(f, name);
88         if (!lbx) {
89                 errmsg("failed to open archive: %s.\n", lbx_strerror());
90                 return EXIT_FAILURE;
91         }
92
93         nfiles = lbx_numfiles(lbx);
94         if (verbose) {
95                 printf("Files in archive: %zu\n", nfiles);
96         }
97
98         for (i = 0; i < nfiles; i++) {
99                 struct lbx_statbuf stat;
100                 size_t rc;
101                 FILE *of;
102                 int j;
103
104                 lbx_stat(lbx, i, &stat);
105
106                 switch (filematch(argv, stat.name)) {
107                 case -1: continue;
108                 case  0: break;
109                 default: goto err;
110                 }
111
112                 of = fopen(stat.name, "wbx");
113                 if (!of) {
114                         errmsg("failed to create output file %s: %m.\n",
115                                                              stat.name);
116                         goto err;
117                 }
118
119                 if (verbose) printf("extracting %s...\n", stat.name);
120                 rc = lbx_extract(lbx, i, of);
121                 if (rc < stat.size) {
122                         if (rc == 0) remove(stat.name);
123                         errmsg("error extracting %s: %s.\n",
124                                stat.name, lbx_strerror());
125                         goto err;
126                 }
127                 if (verbose) printf("wrote %zu bytes.\n", rc);
128         }
129
130         lbx_close(lbx);
131         return EXIT_SUCCESS;
132 err:
133         lbx_close(lbx);
134         return EXIT_FAILURE;
135 }
136
137 int main(int argc, char **argv)
138 {
139         int mode = MODE_NONE, verbose = 0;
140         const char *name = "stdin";
141         FILE *f  = stdin;
142         int opt;
143
144         static const char         *sopts   = "lxf:i:v";
145         static const struct option lopts[] = {
146                 { "list",    0, NULL, 'l' },
147                 { "extract", 0, NULL, 'x' },
148
149                 { "file",    1, NULL, 'f' },
150                 { "index",   1, NULL, 'i' },
151
152                 { "verbose", 0, NULL, 'v' },
153
154                 { 0 }
155         };
156
157         progname = "lbxtool"; /* argv[0]; */
158         while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
159                 switch(opt) {
160                 case 'l':
161                         mode = MODE_LIST;
162                         break;
163                 case 'x':
164                         mode = MODE_EXTRACT;
165                         break;
166                 case 'f':
167                         if (strcmp(optarg, "-") == 0)
168                                 break;
169
170                         name = strrchr(optarg, '/');
171                         name = name ? name+1 : optarg;
172
173                         f = fopen(optarg, "rb");
174                         if (!f) {
175                                 errmsg("failed to open file %s: %m\n", optarg);
176                                 return EXIT_FAILURE;
177                         }
178                         break;
179                 case 'i':
180                         /* FIXME: Add index file support. */
181                         break;
182                 case 'v':
183                         verbose = 1;
184                         break;
185                 default:
186                         return EXIT_FAILURE;
187                 }
188         }
189
190         switch (mode) {
191         case MODE_LIST:
192                 return list(f, name, verbose, &argv[optind]);
193         case MODE_EXTRACT:
194                 return extract(f, name, verbose, &argv[optind]);
195         }
196
197         fprintf(stderr, "%s: you must specify a mode.\n", progname);
198         return EXIT_FAILURE;
199 }