#line 1026 "../../src/builtin/snarf.m4"
/* -*- buffer-read-only: t -*- vi: set ro:
   THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
*/
#line 1026
#ifdef HAVE_CONFIG_H
#line 1026
# include <config.h>
#line 1026
#endif
#line 1026
#include <sys/types.h>
#line 1026

#line 1026
#include "mailfromd.h"
#line 1026
#include "prog.h"
#line 1026
#include "builtin.h"
#line 1026

#line 1026

#line 1066 "../../src/builtin/snarf.m4"

/* End of snarf.m4 */
#line 1 "sprintf.bi"
/* This file is part of Mailfromd.             -*- c -*-
   Copyright (C) 2007-2025 Sergey Poznyakoff

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */



#define FMT_ALTPOS         0x01 
#define FMT_ALTERNATE      0x02
#define FMT_PADZERO        0x04
#define FMT_ADJUST_LEFT    0x08
#define FMT_SPACEPFX       0x10
#define FMT_SIGNPFX        0x20

typedef enum {
	fmts_copy,      /* Copy char as is */
	fmts_pos,       /* Expect argument position -- %_2$ */
	fmts_flags,     /* Expect flags -- %2$_# */
	fmts_width,     /* Expect width -- %2$#_8 or %2$#_* */
	fmts_width_arg, /* Expect width argument position -- %2$#*_1$ */
	fmts_prec,      /* Expect precision */ 
	fmts_prec_arg,  /* Expect precision argument position */
	fmts_conv       /* Expect conversion specifier */
} printf_format_state;

static int
get_num(const char *p, int i, unsigned *pn)
{
	unsigned n = 0;

	for (; p[i] && mu_isdigit(p[i]); i++) 
		n = n * 10 + p[i] - '0';
	*pn = n;
	return i;
}

#define __MF_MAX(a,b) ((a)>(b) ? (a) : (b))
#define SPRINTF_BUF_SIZE (__MF_MAX(3*sizeof(long), NUMERIC_BUFSIZE_BOUND) + 2)

void
#line 51
bi_sprintf(eval_environ_t env)
#line 51

#line 51

#line 51 "sprintf.bi"
{
#line 51
	
#line 51

#line 51
        char * MFL_DATASEG format;
#line 51
        
#line 51
        long __bi_argcnt;
#line 51
        get_numeric_arg(env, 0, &__bi_argcnt);
#line 51
        get_string_arg(env, 1, &format);
#line 51
        
#line 51
        adjust_stack(env, __bi_argcnt + 1);
#line 51

#line 51

#line 51
	if (builtin_module_trace(BUILTIN_IDX_sprintf))
#line 51
		prog_trace(env, "sprintf %s",format);;
#line 51

{
	int i = 0;
	int cur = 0;
	int start;
	char buf[SPRINTF_BUF_SIZE];
	printf_format_state state = fmts_copy;
	int flags = 0;
	unsigned width = 0;
	unsigned prec = 0;
	unsigned argnum;

	heap_obstack_begin(env);
	
#line 64
unroll_stack(env, __bi_argcnt + 1);
	while (format[cur]) {
		unsigned n;
		char *str;
		long num;
		int negative;
		char fmtbuf[] = { '%', 'x', 0 };
		
		switch (state) {
		case fmts_copy:
			/* Expect `%', and copy all the rest verbatim */
			if (format[cur] == '%') {
				start = cur;
				state = fmts_pos;
				flags = 0;
				width = 0;
				prec = 0;
			} else
				do { char __c = format[cur]; heap_obstack_grow(env, &__c, 1); } while(0);
			cur++;
			break;
				
		case fmts_pos:
			/* Expect '%' or an argument position -- %_% or %_2$ */
			if (format[cur] == '%') {
				do { char __c = '%'; heap_obstack_grow(env, &__c, 1); } while(0);
				cur++;
				state = fmts_copy;
				break;
			}
			if (mu_isdigit(format[cur])) {
				int pos = get_num(format, cur, &n);
				if (format[pos] == '$') {
					argnum = n - 1;
					flags |= FMT_ALTPOS;
					cur = pos + 1;
				}
			}
			state = fmts_flags;    
			break;    
				
		case fmts_flags:
			/* Expect flags -- %2$_# */
			switch (format[cur]) {
			case '#':
				flags |= FMT_ALTERNATE;
				cur++;
				break;
				
			case '0':
				flags |= FMT_PADZERO;
				cur++;
				break;
				
			case '-':
				flags |= FMT_ADJUST_LEFT;
				cur++;
				break;
				
			case ' ':
				flags |= FMT_SPACEPFX;
				cur++;
				break;
				
			case '+':
				flags |= FMT_SIGNPFX;
				cur++;
				break;

			default:
				state = fmts_width;
			}
			break;
			
		case fmts_width:
			/* Expect width -- %2$#_8 or %2$#_* */
			if (mu_isdigit(format[cur])) {
				cur = get_num(format, cur, &width);
				state = fmts_prec;
			} else if (format[cur] == '*') {
				cur++;
				state = fmts_width_arg;
			} else
				state = fmts_prec;
			break;
			
		case fmts_width_arg:
			/* Expect width argument position -- %2$#*_1$ */
			state = fmts_prec;
			if (mu_isdigit(format[cur])) {
				int pos = get_num(format, cur, &n);
				if (format[pos] == '$') {
					
#line 156
 ((__bi_argcnt > (n-1+1)) ?   get_numeric_arg(env, (n-1+1) + 1, &num) :   ((
#line 156
	env_throw_bi(env, mfe_range, "sprintf", "Argument %u is not supplied",(unsigned) (n-1+1))
#line 156
),(long ) 0));
					cur = pos + 1;
					if (num < 0) {
						flags |= FMT_SPACEPFX;
						num = - num;
					}
					width = (unsigned) num;
					break;
				}
			}
			
#line 166
 ((__bi_argcnt > (i+1)) ?   get_numeric_arg(env, (i+1) + 1, &num) :   ((
#line 166
	env_throw_bi(env, mfe_range, "sprintf", "Argument %u is not supplied",(unsigned) (i+1))
#line 166
),(long ) 0));
			i++;
			if (num < 0) {
				/* A negative field width is taken
				   as a `-' flag followed by a positive field width. */
				flags |= FMT_SPACEPFX;
				num = - num;
			}
			width = (unsigned) num;
			break;
			
		case fmts_prec:
			/* Expect precision -- %2$#*1$_. */
			state = fmts_conv;
			if (format[cur] == '.') {
				cur++;
				if (mu_isdigit(format[cur])) {
					cur = get_num(format, cur, &prec);
				} else if (format[cur] == '*') {
					cur++;
					state = fmts_prec_arg;
				}
			} 
			break;
			
		case fmts_prec_arg:
                        /* Expect precision argument position --
			                %2$#*1$.*_3$ */
			state = fmts_conv;
			if (mu_isdigit(format[cur])) {
				int pos = get_num(format, cur, &n);
				if (format[pos] == '$') {
					
#line 198
 ((__bi_argcnt > (n-1+1)) ?   get_numeric_arg(env, (n-1+1) + 1, &num) :   ((
#line 198
	env_throw_bi(env, mfe_range, "sprintf", "Argument %u is not supplied",(unsigned) (n-1+1))
#line 198
),(long ) 0));
					if (num > 0)
						prec = (unsigned) num;
					cur = pos + 1;
					break;
				}
			}
			
#line 205
 ((__bi_argcnt > (i+1)) ?   get_numeric_arg(env, (i+1) + 1, &num) :   ((
#line 205
	env_throw_bi(env, mfe_range, "sprintf", "Argument %u is not supplied",(unsigned) (i+1))
#line 205
),(long ) 0));
			i++;
			if (num > 0)
				prec = (unsigned) num;
			break;
			
		case fmts_conv:       /* Expect conversion specifier */
			if (!(flags & FMT_ALTPOS))
				argnum = i++;
			switch (format[cur]) {
			case 's':
				
#line 216
 ((__bi_argcnt > (argnum+1)) ?   get_string_arg(env, (argnum+1) + 1, &str) :   ((
#line 216
	env_throw_bi(env, mfe_range, "sprintf", "Argument %u is not supplied",(unsigned) (argnum+1))
#line 216
),(char * MFL_DATASEG) 0));
				n = strlen(str);
				if (prec && prec < n)
					n = prec;
				if (width) {
					char *q, *s;
					if (n > width)
						width = n;
					q = s = mf_c_val(heap_tempspace(env, width + 1), ptr);
					q[width] = 0;
					memset(q, ' ', width);
					if (!(flags & FMT_ADJUST_LEFT)
					    && n < width) {
						s = q + width - n;
					} 
					memcpy(s, str, n);
					str = q;
					n = width;
				}
				heap_obstack_grow(env, str, n);
				break;

			case 'i':
			case 'd':
				
#line 240
 ((__bi_argcnt > (argnum+1)) ?   get_numeric_arg(env, (argnum+1) + 1, &num) :   ((
#line 240
	env_throw_bi(env, mfe_range, "sprintf", "Argument %u is not supplied",(unsigned) (argnum+1))
#line 240
),(long ) 0));
				if (num < 0) {
					negative = 1;
					num = - num;
				} else
					negative = 0;
				/* If a precision is given with a
				   numeric conversion, the 0 flag is ignored.
				 */
				/* A - overrides a 0 if both are given. */
				if (prec || (flags & FMT_ADJUST_LEFT))
					flags &= ~FMT_PADZERO;
				snprintf(buf+1, sizeof(buf)-1, "%ld", num);
				str = buf + 1;
				n = strlen(str);
				if (prec && prec > n) {
					memmove(str + prec - n, str, n + 1);
					memset(str, '0', prec - n);
				}
				
				if (flags & FMT_SIGNPFX) {
					buf[0] = negative ? '-' : '+';
					str = buf;
				} else if (flags & FMT_SPACEPFX) {
					buf[0] = negative ? '-' : ' ';
					str = buf;
				} else if (negative) {
					buf[0] = '-';
					str = buf;
				} else
					str = buf + 1;
				n = strlen(str);

				if (width && width > n) {
					char *q;
					q = heap_obstack_grow(env, NULL, width);
					memset(q,
					       (flags & FMT_PADZERO) ?
					         '0' : ' ',
					       width);
					if (flags & FMT_ADJUST_LEFT) 
						memcpy(q, str, n);
					else {
						if ((flags & FMT_PADZERO) &&
						    str == buf) {
							q[0] = *str++;
							n--;
						}
						memcpy(q + width - n, str, n);
					}
				} else
					heap_obstack_grow(env, str, n);
				break;

			case 'u':
				
#line 295
 ((__bi_argcnt > (argnum+1)) ?   get_numeric_arg(env, (argnum+1) + 1, &num) :   ((
#line 295
	env_throw_bi(env, mfe_range, "sprintf", "Argument %u is not supplied",(unsigned) (argnum+1))
#line 295
),(long ) 0));
				/* If a precision is given with a
				   numeric conversion, the 0 flag is ignored.
				*/
				/* A - overrides a 0 if both are given.*/
				if (prec || (flags & FMT_ADJUST_LEFT))
					flags &= ~FMT_PADZERO;
				snprintf(buf, sizeof(buf), "%lu", num);
				str = buf;
				n = strlen(str);
				if (prec && prec > n) {
					memmove(str + prec - n, str, n + 1);
					memset(str, '0', prec - n);
					n = prec;
				}
				
				if (width && width > n) {
					char *q;
					q = heap_obstack_grow(env, NULL, width);
					memset(q,
					       (flags & FMT_PADZERO) ?
					         '0' : ' ',
					       width);
					if (flags & FMT_ADJUST_LEFT) 
						memcpy(q, str, n);
					else 
						memcpy(q + width - n, str, n);
				} else
					heap_obstack_grow(env, str, n);
				break;

			case 'x':
			case 'X':
				
#line 328
 ((__bi_argcnt > (argnum+1)) ?   get_numeric_arg(env, (argnum+1) + 1, &num) :   ((
#line 328
	env_throw_bi(env, mfe_range, "sprintf", "Argument %u is not supplied",(unsigned) (argnum+1))
#line 328
),(long ) 0));
				/* If a precision is given with a
				   numeric conversion, the 0 flag is ignored.
				*/
				/* A - overrides a 0 if both are given.*/
				if (prec || (flags & FMT_ADJUST_LEFT))
					flags &= ~FMT_PADZERO;
				fmtbuf[1] = format[cur];
				snprintf(buf+2, sizeof(buf)-2, fmtbuf, num);
				str = buf + 2;
				n = strlen(str);
				if (prec && prec > n) {
					memmove(str + prec - n, str, n + 1);
					memset(str, '0', prec - n);
					n = prec;
				}

				if (flags & FMT_ALTERNATE) {
					*--str = format[cur];
					*--str = '0';
					n += 2;
				}
				
				if (width && width > n) {
					char *q;
					q = heap_obstack_grow(env, NULL, width);
					memset(q,
					       (flags & FMT_PADZERO) ?
					         '0' : ' ',
					       width);
					if (flags & FMT_ADJUST_LEFT) 
						memcpy(q, str, n);
					else {
						if (flags & FMT_ALTERNATE
						    && flags & FMT_PADZERO) {
							q[0] = *str++;
							q[1] = *str++;
							n -= 2;
						}
						memcpy(q + width - n, str, n);
					}
				} else
					heap_obstack_grow(env, str, n);
				break;
				
			case 'o':
				
#line 374
 ((__bi_argcnt > (argnum+1)) ?   get_numeric_arg(env, (argnum+1) + 1, &num) :   ((
#line 374
	env_throw_bi(env, mfe_range, "sprintf", "Argument %u is not supplied",(unsigned) (argnum+1))
#line 374
),(long ) 0));
				/* If a precision is given with a
				   numeric conversion, the 0 flag is ignored.
				*/
				/* A - overrides a 0 if both are given.*/
				if (prec || (flags & FMT_ADJUST_LEFT))
					flags &= ~FMT_PADZERO;
				snprintf(buf+1, sizeof(buf)-1, "%lo", num);
				str = buf + 1;
				n = strlen(str);
				if (prec && prec > n) {
					memmove(str + prec - n, str, n + 1);
					memset(str, '0', prec - n);
				}

				if ((flags & FMT_ALTERNATE) && *str != '0') {
					*--str = '0';
					n++;
				}
				
				if (width && width > n) {
					char *q;
					q = heap_obstack_grow(env, NULL, width);
					memset(q,
					       (flags & FMT_PADZERO) ?
					         '0' : ' ',
					       width);
					if (flags & FMT_ADJUST_LEFT) 
						memcpy(q, str, n);
					else 
						memcpy(q + width - n, str, n);
				} else
					heap_obstack_grow(env, str, n);
				break;
				
			default:
				heap_obstack_grow(env, &format[start], cur - start + 1);
#line 412
			}
			
			cur++;
			state = fmts_copy;
		}
	}
	do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);
	adjust_stack(env, __bi_argcnt + 1);
	
#line 420
do {
#line 420
  push(env, (STKVAL) (heap_obstack_finish(env)));
#line 420
  goto endlab;
#line 420
} while (0);
}
endlab:
#line 422
        env_function_cleanup_flush(env, CLEANUP_RETURN);
#line 422
	return;
#line 422
}

#line 1026 "../../src/builtin/snarf.m4"

#line 1026

#line 1026

#line 1026
void
#line 1026
sprintf_init_builtin(void)
#line 1026
{
#line 1026
	
#line 1026
	#line 51 "sprintf.bi"
va_builtin_install_ex("sprintf", bi_sprintf, 0, dtype_string, 1, 0, 0|MFD_BUILTIN_VARIADIC|MFD_BUILTIN_NO_PROMOTE, dtype_string);

#line 1026 "../../src/builtin/snarf.m4"
	
#line 1026
}
#line 1026 "../../src/builtin/snarf.m4"

