/*
 * mpformat.c
 *
 *          hacked up from Tcl 7.6 tclExpr.c file
 *          and some from 'calc'.
 *
 * Copyright 1998 Tom Poindexter
 *
 * copyright notices from borrowed code:
 *
 *---------------------------------------------------------------------------
 * Copyright (c) 1994 David I. Bell
 * Permission is granted to use, distribute, or modify this source,
 * provided that this copyright notice remains intact.
 *
 *---------------------------------------------------------------------------
 *
 */

#include "mpexpr.h"


EXTERN void	Qprintf _ANSI_ARGS_((int argc, CONST86 char **argv));

int
Mp_FormatString(interp, argc, argv)
    Tcl_Interp *interp;
    int         argc;
    CONST86 char **argv;
{
    char *string;

    argc--;  		/* skip past command name */
    argv = &argv[1];

    math_divertio();
    Qprintf(argc, argv);
    string = math_getdivertedio();
    Tcl_SetResult(interp, string, TCL_VOLATILE);
    math_cleardiversions();
    ckfree(string);
    return TCL_OK;
}

#define PUTSTR(str)    math_str(str)
#define PUTCHAR(ch)    math_chr(ch)


/*
 * wrapper for qprintf
 */

void
Qprintf (argc, argv)
  int    argc;
  CONST86 char **argv;
{
    CONST char   *fmt = argv[0];
    NUMBER *q, *q2;
    int ch, sign;
    long width, precision;
    int i = 1;
    CONST char *term;
   
    argc--;  /* fmt string was first */

    while ((ch = *fmt++) != '\0') {
    	if (ch == '\\') {
       	    ch = *fmt++;
            switch (ch) {
       	        case 'n': ch = '\n'; break;
                case 'r': ch = '\r'; break;
            	case 't': ch = '\t'; break;
            	case 'f': ch = '\f'; break;
    	    	case 'v': ch = '\v'; break;
    	    	case 'b': ch = '\b'; break;
    	    	case 0:
                    return;
            }
            PUTCHAR(ch);
            continue;
        }
    	if (ch != '%') {
    	    PUTCHAR(ch);
    	    continue;
    	}
        ch = *fmt++;
    	width = 0; 
	precision = 8; 
	sign = 1;

percent:	;
    	switch (ch) {
    	    case 'd':
                if (argc > 0) {
		    q = Atoq(argv[i],&term); i++;  argc--;
		} else { 
		    q = qlink(&_qzero_);
		}
                qprintfd(q, width);
		qfree(q);
    	    	break;
    	    case 'f':
                if (argc > 0) {
		    q = Atoq(argv[i],&term); i++;  argc--;
		    q2 = qround(q,precision);
		} else { 
		    q = qlink(&_qzero_);
		    q2 = qlink(&_qzero_);
		}
    	    	Qprintff(q2, width, precision);
		qfree(q);
		qfree(q2);
    	    	break;
    	    case 'e':
                if (argc > 0) {
		    q = Atoq(argv[i],&term); i++;  argc--;
		} else { 
		    q = qlink(&_qzero_);
		}
    	    	qprintfe_round(q, width, precision);
		qfree(q);
    	    	break;
    	    case 'r':
    	    case 'R':
                if (argc > 0) {
		    q = Atoq(argv[i],&term); i++;  argc--;
		} else { 
		    q = qlink(&_qzero_);
		}
    	        qprintfr(q, width, (BOOL) (ch == 'R'));
		qfree(q);
    	    	break;
    	    case 'N':
                if (argc > 0) {
		    q = Atoq(argv[i],&term); i++;  argc--;
		} else { 
		    q = qlink(&_qzero_);
		}
            	zprintval(q->num, 0L, width);
		qfree(q);
    	    	break;
    	    case 'D':
                if (argc > 0) {
		    q = Atoq(argv[i],&term); i++;  argc--;
		} else { 
		    q = qlink(&_qzero_);
		}
    	    	zprintval(q->den, 0L, width);
		qfree(q);
    	    	break;
    	    case 'o':
                if (argc > 0) {
		    q = Atoq(argv[i],&term); i++;  argc--;
		} else { 
		    q = qlink(&_qzero_);
		}
    	    	qprintfo(q, width);
		qfree(q);
    	    	break;
    	    case 'x':
                if (argc > 0) {
		    q = Atoq(argv[i],&term); i++;  argc--;
		} else { 
		    q = qlink(&_qzero_);
		}
                qprintfx(q, width);
		qfree(q);
    	    	break;
    	    case 'b':
                if (argc > 0) {
		    q = Atoq(argv[i],&term); i++;  argc--;
		} else { 
		    q = qlink(&_qzero_);
		}
    	    	qprintfb(q, width);
		qfree(q);
    	    	break;
	    case 's':
		if (argc > 0) {
		    PUTSTR(argv[i]);
		    argc--; i++;
		}
		break;
	    case 'c':
		if (argc > 0) {
		    PUTCHAR(*argv[i]);
		    argc--; i++;
		}
		break;
            case 0:
    	    	return;
	    case '%':
		PUTCHAR('%');
		break;
    	    case '-':
            	sign = -1;
    	    	ch = *fmt++;
    	    default:
		if (('0' <= ch && ch <= '9') || ch == '.' || ch == '*') {
		    if (ch == '*') {
                        if (argc > 0) {
		            width = atoi(argv[i]); i++;  argc--;
		        } else { 
		            width = 0;
		        }
		    	width = sign * width;
		        ch = *fmt++;
		    } else if (ch != '.') {
			if (ch < '0' || ch > '9') {
			    goto percent;
			}
		    	width = ch - '0';
		    	while ('0' <= (ch = *fmt++) && ch <= '9') {
			        width = width * 10 + ch - '0';
			}
			width *= sign;
		    }
		    if (ch == '.') {
		        if ((ch = *fmt++) == '*') {
                            if (argc > 0) {
		                precision = atoi(argv[i]); i++;  argc--;
		            } else { 
		                precision = 8;
		            }
		 	    ch = *fmt++;
		        } else {
			    if (ch < '0' || ch > '9') {
			        goto percent;
			    }
			    precision = ch - '0';
			    while ('0' <= (ch = *fmt++) && ch <= '9') {
			    	 precision = precision * 10 + ch - '0';
			    }
			}
	            }
    	            goto percent;
	        }
        }
    }
}


