/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
*          Copyright (c) 2020-2023 Contributors to ksh 93u+m           *
*                      and is licensed under the                       *
*                 Eclipse Public License, Version 2.0                  *
*                                                                      *
*                A copy of the License is available at                 *
*      https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html      *
*         (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d)         *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Phong Vo <kpv@research.att.com>                    *
*                  Martijn Dekker <martijn@inlv.org>                   *
*            Johnothan King <johnothanking@protonmail.com>             *
*                                                                      *
***********************************************************************/

/*
 * catopen intercept
 * the AST catalogs are checked first
 * the AST mc* and native cat* routines do all the work
 * catalogs found by mcfind() are converted from UTF to UCS
 *
 * nl_catd is cast to void*
 * this is either an Mc_t* (Mc_t.set != 0)
 * or a Cc_t* where Cc_t.cat is the native nl_catd
 */

#include <ast.h>
#include <mc.h>
#include <nl_types.h>
#include <iconv.h>

#ifndef DEBUG_trace
#define DEBUG_trace		0
#endif
#if DEBUG_trace
#undef setlocale
#endif

#if _lib_catopen

#undef	nl_catd
#undef	catopen
#undef	catgets
#undef	catclose

typedef struct
{
	Mcset_t*	set;
	nl_catd		cat;
	iconv_t		cvt;
	Sfio_t*		tmp;
} Cc_t;

#else

#define _ast_nl_catd	nl_catd
#define _ast_catopen	catopen
#define _ast_catgets	catgets
#define _ast_catclose	catclose

#endif

_ast_nl_catd
_ast_catopen(const char* name, int flag)
{
	Mc_t*		mc;
	char*		s;
	Sfio_t*		ip;
	char		path[PATH_MAX];

	/*
	 * first try the AST catalogs
	 */

#if DEBUG_trace
sfprintf(sfstderr, "AHA#%d:%s %s LC_MESSAGES=%s:%s\n", __LINE__, __FILE__, name, _ast_setlocale(LC_MESSAGES, 0), setlocale(LC_MESSAGES, 0));
#endif
	if ((s = mcfind(NULL, name, LC_MESSAGES, flag, path, sizeof(path))) && (ip = sfopen(NULL, s, "r")))
	{
#if DEBUG_trace
sfprintf(sfstderr, "AHA#%d:%s %s\n", __LINE__, __FILE__, s);
#endif
		mc = mcopen(ip);
		sfclose(ip);
		if (mc)
			return (_ast_nl_catd)mc;
	}
#if _lib_catopen
	if (strcmp(setlocale(LC_MESSAGES, NULL), "debug"))
	{
		Cc_t*		cc;
		nl_catd		d;

		/*
		 * now the native catalogs
		 */

		if (s && (d = catopen(s, flag)) != (nl_catd)(-1) || !(s = 0) && (d = catopen(name, flag)) != (nl_catd)(-1))
		{
			if (!(cc = newof(0, Cc_t, 1, 0)))
			{
				catclose(d);
				return (_ast_nl_catd)(-1);
			}
			cc->cat = d;
			if ((s || *name == '/') && (ast.locale.set & (1<<AST_LC_MESSAGES)))
			{
				if ((cc->cvt = iconv_open("", "utf")) == (iconv_t)(-1) || !(cc->tmp = sfstropen()))
				{
					catclose(d);
					free(cc);
					return (_ast_nl_catd)(-1);
				}
			}
			else
				cc->cvt = (iconv_t)(-1);
#if DEBUG_trace
sfprintf(sfstderr, "AHA#%d:%s %s %s native %p\n", __LINE__, __FILE__, s, name, cc->cat);
#endif
			return (_ast_nl_catd)cc;
		}
	}
#endif

	/*
	 * loser
	 */

	return (_ast_nl_catd)(-1);
}

char*
_ast_catgets(_ast_nl_catd cat, int set, int num, const char* msg)
{
	if (cat == (_ast_nl_catd)(-1))
		return (char*)msg;
#if _lib_catopen
	if (!((Cc_t*)cat)->set)
	{
		char*	s;
		size_t	n;

		msg = (char*)catgets(((Cc_t*)cat)->cat, set, num, msg);
		if (((Cc_t*)cat)->cvt != (iconv_t)(-1))
		{
			s = (char*)msg;
			n = strlen(s);
			iconv_write(((Cc_t*)cat)->cvt, ((Cc_t*)cat)->tmp, &s, &n, NULL);
			if (s = sfstruse(((Cc_t*)cat)->tmp))
				return s;
		}
		return (char*)msg;
	}
#endif
	return mcget((Mc_t*)cat, set, num, msg);
}

int
_ast_catclose(_ast_nl_catd cat)
{
	if (cat == (_ast_nl_catd)(-1))
		return -1;
#if _lib_catopen
	if (!((Cc_t*)cat)->set)
	{
		if (((Cc_t*)cat)->cvt != (iconv_t)(-1))
			iconv_close(((Cc_t*)cat)->cvt);
		if (((Cc_t*)cat)->tmp)
			sfclose(((Cc_t*)cat)->tmp);
		return catclose(((Cc_t*)cat)->cat);
	}
#endif
	return mcclose((Mc_t*)cat);
}
