Current section
Files
Jump to
Current section
Files
c_src/hashids.c/src/main.c
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include "hashids.h"
enum { COMMAND_ENCODE = 0, COMMAND_DECODE = 1 };
static void
usage(const char *program_invocation_name, FILE *out)
{
fputs("\n", out);
fputs("Usage:\n", out);
fprintf(out, " %s [options] <arguments>\n",
program_invocation_name);
fputs("\n", out);
fputs("Options:\n", out);
fputs(" -e, --encode set command to encode (default)\n", out);
fputs(" -d, --decode set command to decode\n", out);
fputs(" -s, --salt set salt [" HASHIDS_DEFAULT_SALT "]\n", out);
fputs(" -a, --alphabet set alphabet [" HASHIDS_DEFAULT_ALPHABET "]\n",
out);
fprintf(out, " -l, --min-length set hash minimum length [%u]\n",
HASHIDS_DEFAULT_MIN_HASH_LENGTH);
fputs(" -x, --hex encode / decode hex strings\n", out);
fputs(" -h, --help display this help and exit\n", out);
fputs(" -v, --version print version information and exit\n", out);
fputs("\n", out);
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
}
static unsigned long long
parse_number(const char *s, char **p)
{
int radix = 10;
if (*s == '0') {
radix = 8;
++s;
if (*s == 'x' || *s == 'X') {
radix = 16;
++s;
}
}
return strtoull(s, p, radix);
}
int
main(int argc, char **argv)
{
hashids_t *hashids;
char *salt = HASHIDS_DEFAULT_SALT, *alphabet = HASHIDS_DEFAULT_ALPHABET,
*buffer, *p, str[18];
unsigned int command = COMMAND_ENCODE, hex = 0;
size_t min_hash_length = HASHIDS_DEFAULT_MIN_HASH_LENGTH, numbers_count;
unsigned long long number, *numbers, *numbers_ptr;
int ch, i, j;
static const struct option longopts[] = {
{"encode", no_argument, NULL, 'e'},
{"decode", no_argument, NULL, 'd'},
{"salt", required_argument, NULL, 's'},
{"alphabet", required_argument, NULL, 'a'},
{"min-length", required_argument, NULL, 'l'},
{"hex", no_argument, NULL, 'x'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0}
};
/* parse command line options */
while ((ch = getopt_long(argc, argv, "+eds:a:l:xhv", longopts,
NULL)) != -1) {
switch (ch) {
case 'e':
command = COMMAND_ENCODE;
break;
case 'd':
command = COMMAND_DECODE;
break;
case 's':
salt = optarg;
break;
case 'a':
alphabet = optarg;
break;
case 'l':
min_hash_length = strtoul(optarg, &p, 10);
if (p == optarg) {
fprintf(stderr, "Invalid minimum length: %s\n", optarg);
return EXIT_FAILURE;
}
break;
case 'x':
hex = 1;
break;
case 'h':
usage(argv[0], stdout);
break;
case 'v':
puts(HASHIDS_VERSION);
return EXIT_SUCCESS;
default:
usage(argv[0], stderr);
}
}
/* no arguments? */
if (optind == argc) {
usage(argv[0], stderr);
}
/* initialize hashids */
hashids = hashids_init3(salt, min_hash_length, alphabet);
/* error checking */
if (!hashids) {
switch (hashids_errno) {
case HASHIDS_ERROR_ALLOC:
fputs("Hashids: Allocation failed\n", stderr);
break;
case HASHIDS_ERROR_ALPHABET_LENGTH:
fputs("Hashids: Alphabet is too short\n", stderr);
break;
case HASHIDS_ERROR_ALPHABET_SPACE:
fputs("Hashids: Alphabet contains whitespace characters\n",
stderr);
break;
default:
fputs("Hashids: Unknown error\n", stderr);
break;
}
return EXIT_FAILURE;
}
/* encode */
if (command == COMMAND_ENCODE) {
/* hex mode */
if (hex) {
number = (unsigned long long)-1;
buffer = (char *)calloc(
hashids_estimate_encoded_size(hashids, 1, &number), 1);
if (!buffer) {
fputs("Cannot allocate memory for buffer\n", stderr);
hashids_free(hashids);
return EXIT_FAILURE;
}
for (i = optind; i < argc; ++i) {
hashids_encode_hex(hashids, buffer, argv[i]);
printf("%s\n", buffer);
}
free(buffer);
hashids_free(hashids);
return EXIT_SUCCESS;
}
/* collect numbers */
numbers_count = argc - optind;
numbers = (unsigned long long *)calloc(numbers_count,
sizeof(unsigned long long));
numbers_ptr = numbers;
if (!numbers) {
fprintf(stderr, "Cannot allocate memory for numbers\n");
hashids_free(hashids);
return EXIT_FAILURE;
}
for (i = optind; i < argc; ++i) {
*numbers_ptr++ = parse_number(argv[i], &p);
if (p == argv[i]) {
fprintf(stderr, "Invalid number: %s\n", argv[i]);
free(numbers);
hashids_free(hashids);
return EXIT_FAILURE;
}
}
/* allocate output buffer */
buffer = (char *)calloc(hashids_estimate_encoded_size(hashids,
numbers_count, numbers), 1);
if (!buffer) {
fprintf(stderr, "Cannot allocate memory for buffer\n");
free(numbers);
hashids_free(hashids);
return EXIT_FAILURE;
}
/* encode, print, cleanup */
hashids_encode(hashids, buffer, numbers_count, numbers);
printf("%s\n", buffer);
free(buffer);
free(numbers);
hashids_free(hashids);
return EXIT_SUCCESS;
}
/* decode */
if (hex) {
for (i = optind; i < argc; ++i) {
hashids_decode_hex(hashids, argv[i], str);
printf("%s\n", str);
}
hashids_free(hashids);
return EXIT_SUCCESS;
}
for (i = optind; i < argc; ++i) {
numbers_count = hashids_numbers_count(hashids, argv[i]);
if (!numbers_count) {
switch (hashids_errno) {
case HASHIDS_ERROR_INVALID_HASH:
fprintf(stderr, "Hashids: Invalid hash: %s\n", argv[i]);
break;
default:
fputs("Hashids: Unknown error\n", stderr);
break;
}
hashids_free(hashids);
return EXIT_FAILURE;
}
numbers = (unsigned long long *)calloc(numbers_count,
sizeof(unsigned long long));
if (!numbers) {
fprintf(stderr, "Cannot allocate memory for numbers\n");
hashids_free(hashids);
return EXIT_FAILURE;
}
if (hashids_decode_safe(hashids, argv[i], numbers, numbers_count) !=
numbers_count) {
fprintf(stderr, "Could not decode numbers properly\n");
hashids_free(hashids);
return EXIT_FAILURE;
}
for (j = 0; j < numbers_count; ++j) {
printf("%llu", numbers[j]);
if (j + 1 < numbers_count) {
printf(" ");
}
}
printf("\n");
free(numbers);
}
return EXIT_SUCCESS;
}