xref: /freebsd/usr.bin/bintrans/bintrans.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2022 The FreeBSD Foundation
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <getopt.h>
30 #include <libgen.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sysexits.h>
36 
37 extern int	main_decode(int, char *[]);
38 extern int	main_encode(int, char *[]);
39 extern int	main_base64_decode(const char *);
40 extern int	main_base64_encode(const char *, const char *);
41 extern int	main_quotedprintable(int, char*[]);
42 
43 static int	search(const char *const);
44 static void	usage_base64(bool);
45 static void	version_base64(void);
46 static void	base64_encode_or_decode(int, char *[]);
47 
48 enum coders {
49 	uuencode, uudecode, b64encode, b64decode, base64, qp
50 };
51 
52 int
53 main(int argc, char *argv[])
54 {
55 	const char *const progname = getprogname();
56 	int coder = search(progname);
57 
58 	if (coder == -1 && argc > 1) {
59 		argc--;
60 		argv++;
61 		coder = search(argv[0]);
62 	}
63 	switch (coder) {
64 	case uuencode:
65 	case b64encode:
66 		main_encode(argc, argv);
67 		break;
68 	case uudecode:
69 	case b64decode:
70 		main_decode(argc, argv);
71 		break;
72 	case base64:
73 		base64_encode_or_decode(argc, argv);
74 		break;
75 	case qp:
76 		main_quotedprintable(argc, argv);
77 		break;
78 	default:
79 		(void)fprintf(stderr,
80 		    "usage: %1$s <uuencode | uudecode> ...\n"
81 		    "       %1$s <b64encode | b64decode> ...\n"
82 		    "       %1$s <base64> ...\n"
83 		    "       %1$s <qp> ...\n",
84 		    progname);
85 		exit(EX_USAGE);
86 	}
87 }
88 
89 static int
90 search(const char *const progname)
91 {
92 #define DESIGNATE(item) [item] = #item
93 	const char *const known[] = {
94 		DESIGNATE(uuencode),
95 		DESIGNATE(uudecode),
96 		DESIGNATE(b64encode),
97 		DESIGNATE(b64decode),
98 		DESIGNATE(base64),
99 		DESIGNATE(qp)
100 	};
101 
102 	for (size_t i = 0; i < nitems(known); i++)
103 		if (strcmp(progname, known[i]) == 0)
104 			return ((int)i);
105 	return (-1);
106 }
107 
108 static void
109 usage_base64(bool failure)
110 {
111 	(void)fputs("usage: base64 [-w col | --wrap=col] "
112 	    "[-d | --decode] [FILE]\n"
113 	    "       base64 --help\n"
114 	    "       base64 --version\n", stderr);
115 	exit(failure ? EXIT_FAILURE : EXIT_SUCCESS);
116 }
117 
118 static void
119 version_base64(void)
120 {
121 	(void)fputs("FreeBSD base64\n", stderr);
122 	exit(EXIT_SUCCESS);
123 }
124 
125 static void
126 base64_encode_or_decode(int argc, char *argv[])
127 {
128 	int ch;
129 	bool decode = false;
130 	const char *w = NULL;
131 	enum { HELP, VERSION };
132 	static const struct option opts[] =
133 	{
134 		{"decode",	no_argument,		NULL, 'd'},
135 		{"ignore-garbage",no_argument,		NULL, 'i'},
136 		{"wrap",	required_argument,	NULL, 'w'},
137 		{"help",	no_argument,		NULL, HELP},
138 		{"version",	no_argument,		NULL, VERSION},
139 		{NULL,		no_argument,		NULL, 0}
140 	};
141 
142 	while ((ch = getopt_long(argc, argv, "diw:", opts, NULL)) != -1)
143 		switch (ch) {
144 		case 'd':
145 			decode = true;
146 			break;
147 		case 'w':
148 			w = optarg;
149 			break;
150 		case 'i':
151 			/* silently ignore */
152 			break;
153 		case VERSION:
154 			version_base64();
155 			break;
156 		case HELP:
157 		default:
158 			usage_base64(ch == '?');
159 		}
160 
161 	if (decode)
162 		main_base64_decode(argv[optind]);
163 	else
164 		main_base64_encode(argv[optind], w);
165 }
166