/*************************************************************************
 * Copyright (c) 2011 AT&T Intellectual Property
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 *
 * Contributors: Details at https://graphviz.org
 *************************************************************************/

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

#include <inttypes.h>

/*	Internal definitions for sfio.
**	Written by Kiem-Phong Vo
*/

#include	<sfio/sfio.h>
#include	"config.h"

#include	<limits.h>
#include	<stdlib.h>
#include	<string.h>
#include	<stdint.h>
#include	<stddef.h>

#include	<fcntl.h>

#include	<unistd.h>

#include	<errno.h>
#include	<ctype.h>

/* short-hands */
#ifndef uchar
#define uchar		unsigned char
#endif
#ifndef ulong
#define ulong		uint64_t
#endif
#ifndef ushort
#define ushort		unsigned short
#endif

/* function to get the decimal point for local environment */
#include	<locale.h>
#define SFSETLOCALE(decimal,thousand) \
	{ struct lconv*	lv_; \
	  if((decimal) == 0) \
	  { (decimal) = '.'; \
	    if((lv_ = localeconv())) \
	    { if(lv_->decimal_point && lv_->decimal_point[0]) \
	    	(decimal) = lv_->decimal_point[0]; \
	      if(lv_->thousands_sep && lv_->thousands_sep[0]) \
	    	(thousand) = lv_->thousands_sep[0]; \
	    } \
	  } \
	}

    typedef union {
	int i, *ip;
	long l, *lp;
	short h, *hp;
	unsigned ui;
	ulong ul;
	ushort uh;
	long long ll, *llp;
	unsigned long long lu;
	long double ld;
	double d;
	float f;
	char c, *s, **sp;
	void *vp;
	Sffmt_t *ft;
    } Argv_t;

#define LEFTP		'('
#define RIGHTP		')'
#define QUOTE		'\''

#define FMTSET(ft, frm, fv, sz, flgs, wid,pr,bs, ts,ns) \
	((ft->form = (char*)frm), \
	 (ft->fmt = fv), (ft->size = sz), \
	 (ft->flags = (flgs&SFFMT_SET)), \
	 (ft->width = wid), (ft->precis = pr), (ft->base = bs), \
	 (ft->t_str = ts), (ft->n_str = ns) )
#define FMTGET(ft, frm, fv, sz, flgs, wid,pr,bs) \
	((frm = ft->form), (fv = ft->fmt), (sz = ft->size), \
	 (flgs = (flgs&~(SFFMT_SET))|(ft->flags&SFFMT_SET)), \
	 (wid = ft->width), (pr = ft->precis), (bs = ft->base) )
#define FMTCMP(sz, type, maxtype) \
	(sz == sizeof(type) || (sz == 0 && sizeof(type) == sizeof(maxtype)) || \
	 (sz == 64 && sz == sizeof(type)*CHAR_BIT) )

/* format flags&types, must coexist with those in sfio.h */
#define SFFMT_EFORMAT	01000000000	/* sfcvt converting %e  */
#define SFFMT_MINUS	02000000000	/* minus sign           */

#define SFFMT_TYPES	(SFFMT_SHORT|SFFMT_SSHORT | SFFMT_LONG|SFFMT_LLONG|\
			 SFFMT_LDOUBLE | SFFMT_IFLAG|SFFMT_JFLAG| \
			 SFFMT_TFLAG | SFFMT_ZFLAG )

/* type of elements to be converted */
#define SFFMT_INT	001	/* %d,%i                */
#define SFFMT_UINT	002	/* %u,o,x etc.          */
#define SFFMT_FLOAT	004	/* %f,e,g etc.          */
#define SFFMT_BYTE	010	/* %c                   */
#define SFFMT_POINTER	020	/* %p, %n               */
#define SFFMT_CLASS	040	/* %[                   */

#define	SF_RADIX	64	/* maximum integer conversion base */

/* floating point to ascii conversion */
#define SF_MAXEXP10	6
#define SF_FDIGITS	256	/* max allowed fractional digits */
#define SF_IDIGITS	1024	/* max number of digits in int part */
#define SF_MAXDIGITS	(((SF_FDIGITS+SF_IDIGITS)/sizeof(int) + 1)*sizeof(int))

/* tables for numerical translation */
#define _Sfpos10	(_Sftable.sf_pos10)
#define _Sfneg10	(_Sftable.sf_neg10)
#define _Sfdec		(_Sftable.sf_dec)
#define _Sfdigits	(_Sftable.sf_digits)
#define _Sffmtintf	(_Sftable.sf_fmtintf)
#define _Sfcv36		(_Sftable.sf_cv36)
#define _Sfcv64		(_Sftable.sf_cv64)
#define _Sftype		(_Sftable.sf_type)
    typedef struct _sftab_ {
	long double sf_pos10[SF_MAXEXP10]; ///< positive powers of 10
	long double sf_neg10[SF_MAXEXP10]; ///< negative powers of 10
	uchar sf_dec[200];	/* ascii reps of values < 100   */
	char *sf_digits;	/* digits for general bases     */
	const char *(*sf_fmtintf)(const char *);
	uchar sf_cv36[UCHAR_MAX + 1];	/* conversion for base [2-36]   */
	uchar sf_cv64[UCHAR_MAX + 1];	/* conversion for base [37-64]  */
	uchar sf_type[UCHAR_MAX + 1];	/* conversion formats&types     */
    } Sftab_t;

    extern Sftab_t _Sftable;

    extern char *_sfcvt(void *, int, int *, int *, int);

#ifdef __cplusplus
}
#endif
