Changeset View
Standalone View
usr.bin/uuencode/bin2text2bin.c
Show All 20 Lines | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <getopt.h> | |||||
#include <libgen.h> | #include <libgen.h> | ||||
#include <stdbool.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
extern int main_decode(int, char *[]); | extern int main_decode(int, char *[]); | ||||
extern int main_encode(int, char *[]); | extern int main_encode(int, char *[]); | ||||
extern int main_base64_decode(const char *); | |||||
extern int main_base64_encode(const char *, const char *); | |||||
static int search(const char *const); | static int search(const char *const); | ||||
static void usage_base64(bool); | |||||
static void version_base64(void); | |||||
static void base64_encode_or_decode(int, char *[]); | |||||
enum coders { | enum coders { | ||||
uuencode, uudecode, b64encode, b64decode | uuencode, uudecode, b64encode, b64decode, base64 | ||||
}; | }; | ||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
const char *const progname = basename(argv[0]); | const char *const progname = basename(argv[0]); | ||||
int coder = search(progname); | int coder = search(progname); | ||||
if (coder == -1 && argc > 1) { | if (coder == -1 && argc > 1) { | ||||
argc--; | argc--; | ||||
argv++; | argv++; | ||||
coder = search(basename(argv[0])); | coder = search(basename(argv[0])); | ||||
} | } | ||||
switch (coder) { | switch (coder) { | ||||
case uuencode: | case uuencode: | ||||
case b64encode: | case b64encode: | ||||
main_encode(argc, argv); | main_encode(argc, argv); | ||||
break; | break; | ||||
case uudecode: | case uudecode: | ||||
case b64decode: | case b64decode: | ||||
main_decode(argc, argv); | main_decode(argc, argv); | ||||
break; | break; | ||||
case base64: | |||||
base64_encode_or_decode(argc, argv); | |||||
break; | |||||
default: | default: | ||||
(void)fprintf(stderr, | (void)fprintf(stderr, | ||||
"usage: %s <uuencode | uudecode> ...\n" | "usage: %1$s <uuencode | uudecode> ...\n" | ||||
" %s <b64encode | b64decode> ...\n", | " %1$s <b64encode | b64decode> ...\n" | ||||
progname, progname); | " %1$s <base64> ...\n", | ||||
progname); | |||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
search(const char *const progname) | search(const char *const progname) | ||||
{ | { | ||||
#define DESIGNATE(item) [item] = #item | #define DESIGNATE(item) [item] = #item | ||||
const char *const known[] = { | const char *const known[] = { | ||||
DESIGNATE(uuencode), | DESIGNATE(uuencode), | ||||
DESIGNATE(uudecode), | DESIGNATE(uudecode), | ||||
DESIGNATE(b64encode), | DESIGNATE(b64encode), | ||||
DESIGNATE(b64decode) | DESIGNATE(b64decode), | ||||
DESIGNATE(base64) | |||||
}; | }; | ||||
for (size_t i = 0; i < nitems(known); i++) | for (size_t i = 0; i < nitems(known); i++) | ||||
if (strcmp(progname, known[i]) == 0) | if (strcmp(progname, known[i]) == 0) | ||||
return ((int)i); | return ((int)i); | ||||
return (-1); | return (-1); | ||||
} | |||||
static void | |||||
usage_base64(bool failure) | |||||
{ | |||||
(void)fputs("usage: base64 [-w col | --wrap=col] " | |||||
"[-d | --decode] [FILE]\n" | |||||
" base64 --help\n" | |||||
" base64 --version\n", stderr); | |||||
exit(failure ? EXIT_FAILURE : EXIT_SUCCESS); | |||||
} | |||||
static void | |||||
version_base64(void) | |||||
delphij: Could you please replace magic numbers here (`-2` and `-3` below) with symbolic names instead? | |||||
Done Inline ActionsI'll think about what I can do here. The cryptic values were intentional, to limit the number of places you have to update when adding a new option. With getopt_long() it's usually 3: enums, optstring and longopts. It's less with getopt_long_only() since you can omit optstring, and short options work as they're recognized as a prefix of the long option - but that's asking for trouble. pstef: I'll think about what I can do here. The cryptic values were intentional, to limit the number… | |||||
{ | |||||
(void)fputs("FreeBSD base64\n", stderr); | |||||
exit(EXIT_SUCCESS); | |||||
} | |||||
static void | |||||
Not Done Inline ActionsPlease replace this block with a switch/case block. delphij: Please replace this block with a switch/case block. | |||||
Done Inline ActionsIn some incarnations of this loop, I checked for ch < -1 or similar. If I make this a switch and decide to revisit that idea later, I would have to convert the switch again. pstef: In some incarnations of this loop, I checked for ch < -1 or similar. If I make this a switch… | |||||
base64_encode_or_decode(int argc, char *argv[]) | |||||
{ | |||||
int ch; | |||||
bool decode = false; | |||||
const char *w = NULL; | |||||
Not Done Inline ActionsPlease extract this into a static function instead of implementing it here. It would be nice if we can do something more descriptive (e.g. FreeBSD base64(1) or even FreeBSD base64 version X.XXinstead of just FreeBSD as the latter might be surprising for users) by the way. delphij: Please extract this into a static function instead of implementing it here.
It would be nice… | |||||
Done Inline ActionsI thought making this a function wasn't worth the effort as it would only have 1 place calling it. I didn't want to write anything more because I would have to set a new tradition of version numbering of this program that never had it before. The option only exists so that using it is recognized and doesn't invoke an error. pstef: I thought making this a function wasn't worth the effort as it would only have 1 place calling… | |||||
enum { HELP, VERSION }; | |||||
static const struct option opts[] = | |||||
{ | |||||
Not Done Inline ActionsPlease extract this to a static function e.g. usage_base64(). delphij: Please extract this to a static function e.g. `usage_base64()`. | |||||
Done Inline ActionsI can do that, but is it worth it, though? Only one place would call it. pstef: I can do that, but is it worth it, though? Only one place would call it. | |||||
{"decode", no_argument, NULL, 'd'}, | |||||
{"ignore-garbage",no_argument, NULL, 'i'}, | |||||
{"wrap", required_argument, NULL, 'w'}, | |||||
{"help", no_argument, NULL, HELP}, | |||||
{"version", no_argument, NULL, VERSION}, | |||||
{NULL, no_argument, NULL, 0} | |||||
}; | |||||
while ((ch = getopt_long(argc, argv, "diw:", opts, NULL)) != -1) | |||||
switch (ch) { | |||||
case 'd': | |||||
decode = true; | |||||
break; | |||||
case 'w': | |||||
w = optarg; | |||||
break; | |||||
case VERSION: | |||||
version_base64(); | |||||
case HELP: | |||||
default: | |||||
usage_base64(ch == '?'); | |||||
} | |||||
if (decode) | |||||
main_base64_decode(argv[optind]); | |||||
else | |||||
main_base64_encode(argv[optind], w); | |||||
} | } |
Could you please replace magic numbers here (-2 and -3 below) with symbolic names instead? This would help readers to better understanding their meanings.
Usually this is done by defining an enum like:
(Personally I'd probably just use 1 and 2 here)