1 /* @(#)strar.c	1.8 21/08/20 Copyright 2017-2018 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)strar.c	1.8 21/08/20 Copyright 2017-2018 J. Schilling";
6 #endif
7 /*
8  *	Manage a StreamArchive
9  *
10  *	Copyright (c) 2017-2018 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/stdio.h>
27 #include <schily/types.h>
28 #define	GT_COMERR		/* #define comerr gtcomerr */
29 #define	GT_ERROR		/* #define error gterror   */
30 #include <schily/schily.h>
31 #include <schily/stdlib.h>
32 #include <schily/strar.h>
33 #include <schily/nlsdefs.h>
34 
35 LOCAL	BOOL	debug;
36 	BOOL	cflag;
37 	BOOL	xflag;
38 LOCAL	BOOL	tflag;
39 EXPORT	int	verbose;
40 
41 EXPORT	BOOL	Ctime;
42 EXPORT	time_t	now;
43 EXPORT	time_t	sixmonth;
44 
45 LOCAL	char	*options = "help,version,debug,c,x,t,v+,f*,list*,nometa,basemeta";
46 
47 LOCAL	void	usage	__PR((int exitcode));
48 LOCAL	void	pvers	__PR((void));
49 EXPORT	int	main	__PR((int ac, char *av[]));
50 LOCAL	int	create	__PR((strar *info, int ac, char * const av[], FILE *f));
51 LOCAL	int	send	__PR((strar *info, char *name));
52 LOCAL	int	extract	__PR((strar *info));
53 LOCAL	int	list	__PR((strar *info));
54 LOCAL	FILE	*openlist __PR((char *listfile));
55 
56 LOCAL void
usage(exitcode)57 usage(exitcode)
58 	int	exitcode;
59 {
60 	error("Usage:	strar [options] [file1...filen]\n");
61 	error("Options:\n");
62 	error("\t-help\t\tprint this online help\n");
63 	error("\t-version\tprint version number\n");
64 	error("\t-debug\t\tprint additional debug output\n");
65 	error("\t-c\t\tcreate archive with named files\n");
66 	error("\t-x\t\textract archive\n");
67 	error("\t-t\t\tlist archive\n");
68 	error("\t-v\t\tincrement verbose level\n");
69 	error("\tlist=name\tread filenames from named file\n");
70 	error("\t-nometa\t\tdo not add meta data except path and size\n");
71 	error("\t-basemeta\tonly add basic meta data: path, mode, size, filetype\n");
72 	exit(exitcode);
73 }
74 
75 LOCAL void
pvers()76 pvers()
77 {
78 	gtprintf("strar %s %s (%s-%s-%s)\n\n", "1.8", "2021/08/20",
79 		HOST_CPU, HOST_VENDOR, HOST_OS);
80 	gtprintf("Copyright (C) 2017-2021 %s\n", _("J�rg Schilling"));
81 	gtprintf("This is free software; see the source for copying conditions.  There is NO\n");
82 	gtprintf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
83 	exit(0);
84 }
85 
86 int
main(ac,av)87 main(ac, av)
88 	int	ac;
89 	char	*av[];
90 {
91 	int	i;
92 	int	cac;
93 	char	*const *cav;
94 	int	fac;
95 	char	*const *fav;
96 	BOOL	prvers = FALSE;
97 	BOOL	help = FALSE;
98 	BOOL	nometa = FALSE;
99 	BOOL	basemeta = FALSE;
100 	FINFO	finfo;
101 	char	*archive = NULL;
102 	char	*listfile = NULL;
103 	char	*codeset = NULL;
104 
105 	save_args(ac, av);
106 
107 #ifdef	USE_NLS
108 	setlocale(LC_ALL, "");
109 	if (setlocale(LC_ALL, "") != NULL) {
110 #ifdef	CODESET
111 		codeset = nl_langinfo(CODESET);
112 #endif
113 	}
114 
115 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
116 #define	TEXT_DOMAIN "strar"	/* Use this only if it weren't */
117 #endif
118 	{ char	*dir;
119 	dir = searchfileinpath("share/locale", F_OK,
120 					SIP_ANY_FILE|SIP_NO_PATH, NULL);
121 	if (dir)
122 		(void) bindtextdomain(TEXT_DOMAIN, dir);
123 	else
124 #if defined(PROTOTYPES) && defined(INS_BASE)
125 	(void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
126 #else
127 	(void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
128 #endif
129 	(void) textdomain(TEXT_DOMAIN);
130 	}
131 #endif 	/* USE_NLS */
132 
133 
134 	cac = --ac;
135 	cav = ++av;
136 
137 	if (getallargs(&cac, &cav, options, &help, &prvers, &debug,
138 			&cflag, &xflag, &tflag, &verbose, &archive,
139 			&listfile,
140 			&nometa, &basemeta) < 0) {
141 		errmsgno(EX_BAD, _("Bad flag: %s.\n"), cav[0]);
142 		usage(EX_BAD);
143 	}
144 	if (help)
145 		usage(0);
146 	if (prvers)
147 		pvers();
148 
149 	if ((cflag + xflag + tflag) > 1)
150 		comerrno(EX_BAD, _("Only one of -c -x -l.\n"));
151 
152 	fac = ac;
153 	fav = av;
154 	for (i = 0; getfiles(&fac, &fav, options) > 0; i++, fac--, fav++);
155 
156 	if (cflag && i == 0 && listfile == NULL) {
157 		comerrno(EX_BAD,
158 		_("Too few arguments; will not create an empty archive..\n"));
159 	}
160 	if (strar_open(&finfo, archive, 0, cflag ? OM_WRITE : OM_READ,
161 	    codeset) < 0) {
162 		comerr(_("Cannot open archive.\n"));
163 	}
164 	if (finfo.f_fp == stdout) {
165 		finfo.f_list = stderr;
166 		finfo.f_listname = "stderr";
167 	} else {
168 		finfo.f_list = stdout;
169 		finfo.f_listname = "stdout";
170 	}
171 	if (verbose > CMD_VERBOSE)
172 		verbose = CMD_VERBOSE;
173 	finfo.f_cmdflags |= verbose;
174 
175 	if (cflag) {
176 		FILE	*f = NULL;
177 
178 		if (listfile)
179 			f = openlist(listfile);
180 		finfo.f_cmdflags |= CMD_CREATE;
181 		if (nometa)
182 			finfo.f_xflags = 0;
183 		else if (basemeta)
184 			finfo.f_xflags = XF_BASE_FILEMETA;
185 		else
186 			finfo.f_xflags = XF_ALL_FILEMETA;
187 #ifdef	__future__
188 		finfo.f_xflags |= XF_BINARY;
189 #endif
190 		return (create(&finfo, ac, av, f));
191 	} else if (xflag) {
192 		finfo.f_cmdflags |= CMD_XTRACT;
193 		strar_receive(&finfo, extract);
194 	} else if (tflag) {
195 		finfo.f_cmdflags |= CMD_LIST;
196 		strar_receive(&finfo, list);
197 	} else {
198 		errmsgno(EX_BAD, _("No function specified.\n"));
199 		usage(EX_BAD);
200 	}
201 	strar_close(&finfo);
202 	exit(0);
203 }
204 
205 LOCAL int
create(info,ac,av,f)206 create(info, ac, av, f)
207 	strar	*info;
208 	int	ac;
209 	char	* const av[];
210 	FILE	*f;
211 {
212 
213 	strar_archtype(info);
214 	if (f) {
215 		char	*buf = NULL;
216 		size_t	len = 0;
217 		ssize_t	amt;
218 
219 		while ((amt = getdelim(&buf, &len, '\n', f)) >= 0) {
220 			if (buf[amt-1] == '\n')
221 				buf[amt-1] = '\0';
222 			(void) send(info, buf);
223 		}
224 	} else {
225 		for (; getfiles(&ac, &av, options) > 0; ac--, av++) {
226 			if (strar_send(info, av[0]) != 0)
227 				errmsg(_("Cannot archive '%s'.\n"), av[0]);
228 		}
229 	}
230 	strar_eof(info);
231 	return (0);
232 }
233 
234 
235 LOCAL int
send(info,name)236 send(info, name)
237 	strar	*info;
238 	char	*name;
239 {
240 	int	ret;
241 
242 	ret = strar_send(info, name);
243 	if (ret < 0) {
244 		if (ret == -2)
245 			errmsgno(EX_BAD,
246 				_("Skipping '%s', not a file.\n"), name);
247 		else
248 			errmsg(_("Cannot archive '%s'.\n"), name);
249 	}
250 	return (ret);
251 }
252 
253 LOCAL int
extract(info)254 extract(info)
255 	strar	*info;
256 {
257 	return (strar_get(info));
258 }
259 
260 LOCAL int
list(info)261 list(info)
262 	strar	*info;
263 {
264 	strar_list_file(info);
265 	if (info->f_size == 0)
266 		return (0);
267 	strar_skip(info);
268 	return (0);
269 }
270 
271 LOCAL FILE *
openlist(listfile)272 openlist(listfile)
273 	char	*listfile;
274 {
275 	FILE	*listf;
276 
277 	if (streql(listfile, "-")) {
278 		listf = stdin;
279 	} else if ((listf = fileopen(listfile, "r")) == (FILE *)NULL)
280 		comerr(_("Cannot open '%s'.\n"), listfile);
281 
282 	return (listf);
283 }
284