
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void translate(locale_t loc, int err);
static char *get_errno_symbol(int errnum);

int
main(int argc, char **argv)
{
	const char	*localename;
	int			 min_err;
	int			 max_err;
	locale_t	 c_loc;

	setlocale(LC_CTYPE, "");
	setlocale(LC_MESSAGES, "");

	if (argc != 3)
    {
		fprintf(stderr, "usage:\n\terrno_translation min_errno max_errno\n");
		exit(1);
    }

	min_err = atoi(argv[1]);
	max_err = atoi(argv[2]);

	if (min_err >= max_err)
    {
		fprintf(stderr, "min_err must be less than max_err\n");
		exit(1);
    }

	c_loc = newlocale(LC_ALL_MASK, "C", NULL);
	if (!c_loc)
    {
		fprintf(stderr, "can't create locale: C\n");
		exit(1);
    }

	for (int i = min_err; i <= max_err; i++)
		translate(c_loc, i);  
}

static void
translate(locale_t c_loc, int err)
{
	const char	*errorname = get_errno_symbol(err);
	const char	*msgid;
	const char	*msgstr;
	locale_t	 save_loc;

	if (!errorname && err == 0)
		errorname = "0";

	if (!errorname)
		return;

	printf("#. %s\t", errorname);
  
	save_loc = uselocale(c_loc);
	msgid = strerror(err);
	uselocale(save_loc);

	printf("msgid \"%s\"\t", msgid);
  
	msgstr = strerror(err);
	printf("msgstr \"%s\"\t\n", msgstr);
}

/*
 * Returns a symbol (e.g. "ENOENT") for an errno code.
 * Returns NULL if the code is unrecognized.
 */
static char *
get_errno_symbol(int errnum)
{
	switch (errnum)
	{
		case E2BIG:
			return "E2BIG";
		case EACCES:
			return "EACCES";
		case EADDRINUSE:
			return "EADDRINUSE";
		case EADDRNOTAVAIL:
			return "EADDRNOTAVAIL";
		case EAFNOSUPPORT:
			return "EAFNOSUPPORT";
#ifdef EAGAIN
		case EAGAIN:
			return "EAGAIN";
#endif
#ifdef EALREADY
		case EALREADY:
			return "EALREADY";
#endif
		case EBADF:
			return "EBADF";
#ifdef EBADMSG
		case EBADMSG:
			return "EBADMSG";
#endif
		case EBUSY:
			return "EBUSY";
		case ECHILD:
			return "ECHILD";
		case ECONNABORTED:
			return "ECONNABORTED";
		case ECONNREFUSED:
			return "ECONNREFUSED";
		case ECONNRESET:
			return "ECONNRESET";
		case EDEADLK:
			return "EDEADLK";
		case EDOM:
			return "EDOM";
		case EEXIST:
			return "EEXIST";
		case EFAULT:
			return "EFAULT";
		case EFBIG:
			return "EFBIG";
		case EHOSTDOWN:
			return "EHOSTDOWN";
		case EHOSTUNREACH:
			return "EHOSTUNREACH";
		case EIDRM:
			return "EIDRM";
		case EINPROGRESS:
			return "EINPROGRESS";
		case EINTR:
			return "EINTR";
		case EINVAL:
			return "EINVAL";
		case EIO:
			return "EIO";
		case EISCONN:
			return "EISCONN";
		case EISDIR:
			return "EISDIR";
#ifdef ELOOP
		case ELOOP:
			return "ELOOP";
#endif
		case EMFILE:
			return "EMFILE";
		case EMLINK:
			return "EMLINK";
		case EMSGSIZE:
			return "EMSGSIZE";
		case ENAMETOOLONG:
			return "ENAMETOOLONG";
		case ENETDOWN:
			return "ENETDOWN";
		case ENETRESET:
			return "ENETRESET";
		case ENETUNREACH:
			return "ENETUNREACH";
		case ENFILE:
			return "ENFILE";
		case ENOBUFS:
			return "ENOBUFS";
		case ENODEV:
			return "ENODEV";
		case ENOENT:
			return "ENOENT";
		case ENOEXEC:
			return "ENOEXEC";
		case ENOMEM:
			return "ENOMEM";
		case ENOSPC:
			return "ENOSPC";
		case ENOSYS:
			return "ENOSYS";
		case ENOTCONN:
			return "ENOTCONN";
		case ENOTDIR:
			return "ENOTDIR";
		case ENOTEMPTY:
			return "ENOTEMPTY";
		case ENOTSOCK:
			return "ENOTSOCK";
#ifdef ENOTSUP
		case ENOTSUP:
			return "ENOTSUP";
#endif
		case ENOTTY:
			return "ENOTTY";
		case ENXIO:
			return "ENXIO";
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP))
		case EOPNOTSUPP:
			return "EOPNOTSUPP";
#endif
#ifdef EOVERFLOW
		case EOVERFLOW:
			return "EOVERFLOW";
#endif
		case EPERM:
			return "EPERM";
		case EPIPE:
			return "EPIPE";
		case EPROTONOSUPPORT:
			return "EPROTONOSUPPORT";
		case ERANGE:
			return "ERANGE";
#ifdef EROFS
		case EROFS:
			return "EROFS";
#endif
		case ESRCH:
			return "ESRCH";
		case ETIMEDOUT:
			return "ETIMEDOUT";
#ifdef ETXTBSY
		case ETXTBSY:
			return "ETXTBSY";
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
		case EWOULDBLOCK:
			return "EWOULDBLOCK";
#endif
		case EXDEV:
			return "EXDEV";
	}

	return NULL;
}
