コード例 #1
0
ファイル: util.c プロジェクト: yezhejack/QAMining
/* EAM Nov 2012:
 * Unbelievably, the count parameter has been silently ignored or
 * improperly applied ever since this routine was introduced back
 * in version 3.7.  Now fixed to prevent buffer overflow.
 */
void
gprintf(
    char *outstring,
    size_t count,
    char *format,
    double log10_base,
    double x)
{
    char tempdest[MAX_LINE_LEN + 1];
    char temp[MAX_LINE_LEN + 1];
    char *t;
    TBOOLEAN seen_mantissa = FALSE; /* remember if mantissa was already output */
    double stored_power_base = 0;   /* base for the last mantissa output*/
    int stored_power = 0;	/* power matching the mantissa output earlier */
    TBOOLEAN got_hash = FALSE;

    char *dest  = &tempdest[0];
    char *limit = &tempdest[MAX_LINE_LEN];
    static double log10_of_1024; /* to avoid excess precision comparison in check of connection %b -- %B */

    log10_of_1024 = log10(1024);

#define remaining_space (size_t)(limit-dest)

    *dest = '\0';

    set_numeric_locale();

    /* Oct 2013 - default format is now expected to be "%h" */
    if (((term->flags & TERM_IS_LATEX)) && !strcmp(format, DEF_FORMAT))
        format = DEF_FORMAT_LATEX;

    for (;;) {
        /*{{{  copy to dest until % */
        while (*format != '%')
            if (!(*dest++ = *format++) || (remaining_space == 0)) {
                goto done;
            }
        /*}}} */

        /*{{{  check for %% */
        if (format[1] == '%') {
            *dest++ = '%';
            format += 2;
            continue;
        }
        /*}}} */

        /*{{{  copy format part to temp, excluding conversion character */
        t = temp;
        *t++ = '%';
        if (format[1] == '#') {
            *t++ = '#';
            format++;
            got_hash = TRUE;
        }
        /* dont put isdigit first since side effect in macro is bad */
        while (*++format == '.' || isdigit((unsigned char) *format)
                || *format == '-' || *format == '+' || *format == ' '
                || *format == '\'')
            *t++ = *format;
        /*}}} */

        /*{{{  convert conversion character */
        switch (*format) {
        /*{{{  x and o */
        case 'x':
        case 'X':
        case 'o':
        case 'O':
            if (fabs(x) >= (double)INT_MAX) {
                t[0] = 'l';
                t[1] = 'l';
                t[2] = *format;
                t[3] = '\0';
                snprintf(dest, remaining_space, temp, (long long) x);
            } else {
                t[0] = *format;
                t[1] = '\0';
                snprintf(dest, remaining_space, temp, (int) x);
            }
            break;
        /*}}} */
        /*{{{  e, f and g */
        case 'e':
        case 'E':
        case 'f':
        case 'F':
        case 'g':
        case 'G':
            t[0] = *format;
            t[1] = 0;
            snprintf(dest, remaining_space, temp, x);
            break;
        case 'h':
        case 'H':
            /* g/G with enhanced formating (if applicable) */
            t[0] = (*format == 'h') ? 'g' : 'G';
            t[1] = 0;

            if ((term->flags & (TERM_ENHANCED_TEXT | TERM_IS_LATEX)) == 0) {
                /* Not enhanced, not latex, just print it */
                snprintf(dest, remaining_space, temp, x);

            } else if (table_mode) {
                /* Tabular output should contain no markup */
                snprintf(dest, remaining_space, temp, x);

            } else {
                /* in enhanced mode -- convert E/e to x10^{foo} or *10^{foo} */
#define LOCAL_BUFFER_SIZE 256
                char tmp[LOCAL_BUFFER_SIZE];
                char tmp2[LOCAL_BUFFER_SIZE];
                int i,j;
                TBOOLEAN bracket_flag = FALSE;
                snprintf(tmp, 240, temp, x); /* magic number alert: why 240? */
                for (i=j=0; tmp[i] && (i < LOCAL_BUFFER_SIZE); i++) {
                    if (tmp[i]=='E' || tmp[i]=='e') {
                        if ((term-> flags & TERM_IS_LATEX)) {
                            if (*format == 'h') {
                                strcpy(&tmp2[j], "\\times");
                                j+= 6;
                            } else {
                                strcpy(&tmp2[j], "\\cdot");
                                j+= 5;
                            }
                        } else switch (encoding) {
                            case S_ENC_UTF8:
                                strcpy(&tmp2[j], "\xc3\x97"); /* UTF character '×' */
                                j+= 2;
                                break;
                            case S_ENC_CP1252:
                                tmp2[j++] = (*format=='h') ? 0xd7 : 0xb7;
                                break;
                            case S_ENC_ISO8859_1:
                            case S_ENC_ISO8859_2:
                            case S_ENC_ISO8859_9:
                            case S_ENC_ISO8859_15:
                                tmp2[j++] = (*format=='h') ? 0xd7 : '*';
                                break;
                            default:
                                tmp2[j++] = (*format=='h') ? 'x' : '*';
                                break;
                            }

                        strcpy(&tmp2[j], "10^{");
                        j += 4;
                        bracket_flag = TRUE;

                        /* Skip + and leading 0 in exponent */
                        i++; /* skip E */
                        if (tmp[i] == '+')
                            i++;
                        else if (tmp[i] == '-') /* copy sign */
                            tmp2[j++] = tmp[i++];
                        while (tmp[i] == '0')
                            i++;
                        i--; /* undo following loop increment */
                    } else {
                        tmp2[j++] = tmp[i];
                    }
                }
                if (bracket_flag)
                    tmp2[j++] = '}';
                tmp2[j] = '\0';
                strncpy(dest, tmp2, remaining_space);
#undef LOCAL_BUFFER_SIZE
            }

            break;

        /*}}} */
        /*{{{  l --- mantissa to current log base */
        case 'l':
        {
            double mantissa;

            t[0] = 'f';
            t[1] = 0;
            stored_power_base = log10_base;
            mant_exp(stored_power_base, x, FALSE, &mantissa,
                     &stored_power, temp);
            seen_mantissa = TRUE;
            snprintf(dest, remaining_space, temp, mantissa);
            break;
        }
        /*}}} */
        /*{{{  t --- base-10 mantissa */
        case 't':
        {
            double mantissa;

            t[0] = 'f';
            t[1] = 0;
            stored_power_base = 1.0;
            mant_exp(stored_power_base, x, FALSE, &mantissa,
                     &stored_power, temp);
            seen_mantissa = TRUE;
            snprintf(dest, remaining_space, temp, mantissa);
            break;
        }
        /*}}} */
        /*{{{  s --- base-1000 / 'scientific' mantissa */
        case 's':
        {
            double mantissa;

            t[0] = 'f';
            t[1] = 0;
            stored_power_base = 1.0;
            mant_exp(stored_power_base, x, TRUE, &mantissa,
                     &stored_power, temp);
            seen_mantissa = TRUE;
            snprintf(dest, remaining_space, temp, mantissa);
            break;
        }
        /*}}} */
        /*{{{  b --- base-1024 mantissa */
        case 'b':
        {
            double mantissa;

            t[0] = 'f';
            t[1] = 0;
            stored_power_base = log10_of_1024;
            mant_exp(stored_power_base, x, FALSE, &mantissa,
                     &stored_power, temp);
            seen_mantissa = TRUE;
            snprintf(dest, remaining_space, temp, mantissa);
            break;
        }
        /*}}} */
        /*{{{  L --- power to current log base */
        case 'L':
        {
            int power;

            t[0] = 'd';
            t[1] = 0;
            if (seen_mantissa) {
                if (stored_power_base == log10_base) {
                    power = stored_power;
                } else {
                    int_error(NO_CARET, "Format character mismatch: %%L is only valid with %%l");
                }
            } else {
                stored_power_base = log10_base;
                mant_exp(log10_base, x, FALSE, NULL, &power, "%.0f");
            }
            snprintf(dest, remaining_space, temp, power);
            break;
        }
        /*}}} */
        /*{{{  T --- power of ten */
        case 'T':
        {
            int power;

            t[0] = 'd';
            t[1] = 0;
            if (seen_mantissa) {
                if (stored_power_base == 1.0) {
                    power = stored_power;
                } else {
                    int_error(NO_CARET, "Format character mismatch: %%T is only valid with %%t");
                }
            } else {
                mant_exp(1.0, x, FALSE, NULL, &power, "%.0f");
            }
            snprintf(dest, remaining_space, temp, power);
            break;
        }
        /*}}} */
        /*{{{  S --- power of 1000 / 'scientific' */
        case 'S':
        {
            int power;

            t[0] = 'd';
            t[1] = 0;
            if (seen_mantissa) {
                if (stored_power_base == 1.0) {
                    power = stored_power;
                } else {
                    int_error(NO_CARET, "Format character mismatch: %%S is only valid with %%s");
                }
            } else {
                mant_exp(1.0, x, TRUE, NULL, &power, "%.0f");
            }
            snprintf(dest, remaining_space, temp, power);
            break;
        }
        /*}}} */
        /*{{{  c --- ISO decimal unit prefix letters */
        case 'c':
        {
            int power;

            t[0] = 'c';
            t[1] = 0;
            if (seen_mantissa) {
                if (stored_power_base == 1.0) {
                    power = stored_power;
                } else {
                    int_error(NO_CARET, "Format character mismatch: %%c is only valid with %%s");
                }
            } else {
                mant_exp(1.0, x, TRUE, NULL, &power, "%.0f");
            }

            if (power >= -24 && power <= 24) {
                /* name  power   name  power
                   -------------------------
                   yocto  -24    yotta  24
                   zepto  -21    zetta  21
                   atto   -18    Exa    18
                   femto  -15    Peta   15
                   pico   -12    Tera   12
                   nano    -9    Giga    9
                   micro   -6    Mega    6
                   milli   -3    kilo    3   */
                /* -18 -> 0, 0 -> 6, +18 -> 12, ... */
                /* HBB 20010121: avoid division of -ve ints! */
                power = (power + 24) / 3;
                snprintf(dest, remaining_space, temp, "yzafpnum kMGTPEZY"[power]);
            } else {
                /* please extend the range ! */
                /* fall back to simple exponential */
                snprintf(dest, remaining_space, "e%+02d", power);
            }
            break;
        }
        /*}}} */
        /*{{{  B --- IEC 60027-2 A.2 / ISO/IEC 80000 binary unit prefix letters */
        case 'B':
        {
            int power;

            t[0] = 'c';
            t[1] = 'i';
            t[2] = '\0';
            if (seen_mantissa) {
                if (stored_power_base == log10_of_1024) {
                    power = stored_power;
                } else {
                    int_error(NO_CARET, "Format character mismatch: %%B is only valid with %%b");
                }
            } else {
                mant_exp(log10_of_1024, x, FALSE, NULL, &power, "%.0f");
            }

            if (power > 0 && power <= 8) {
                /* name  power
                   -----------
                   Yobi   8
                   Zebi   7
                   Exbi   9
                   Pebi   5
                   Tebi   4
                   Gibi   3
                   Mebi   2
                   kibi   1   */
                snprintf(dest, remaining_space, temp, " kMGTPEZY"[power]);
            } else if (power > 8) {
                /* for the larger values, print x2^{10}Gi for example */
                snprintf(dest, remaining_space, "x2^{%d}Yi", power-8);
            } else if (power < 0) {
                snprintf(dest, remaining_space, "x2^{%d}", power*10);
            } else {
                snprintf(dest, remaining_space, "  ");
            }

            break;
        }
        /*}}} */
        /*{{{  P --- multiple of pi */
        case 'P':
        {
            t[0] = 'f';
            t[1] = 0;
            snprintf(dest, remaining_space, temp, x / M_PI);
            break;
        }
        /*}}} */
        default:
            reset_numeric_locale();
            int_error(NO_CARET, "Bad format character");
        } /* switch */
        /*}}} */

        if (got_hash && (format != strpbrk(format,"oeEfFgG"))) {
            reset_numeric_locale();
            int_error(NO_CARET, "Bad format character");
        }

        /* change decimal '.' to the actual entry in decimalsign */
        if (decimalsign != NULL) {
            char *dotpos1 = dest;
            char *dotpos2;
            size_t newlength = strlen(decimalsign);

            /* dot is the default decimalsign we will be replacing */
            int dot = *get_decimal_locale();

            /* replace every dot by the contents of decimalsign */
            while ((dotpos2 = strchr(dotpos1,dot)) != NULL) {
                if (newlength == 1) {	/* The normal case */
                    *dotpos2 = *decimalsign;
                    dotpos1++;
                } else {		/* Some multi-byte decimal marker */
                    size_t taillength = strlen(dotpos2);
                    dotpos1 = dotpos2 + newlength;
                    if (dotpos1 + taillength > limit)
                        int_error(NO_CARET,
                                  "format too long due to decimalsign string");
                    /* move tail end of string out of the way */
                    memmove(dotpos1, dotpos2 + 1, taillength);
                    /* insert decimalsign */
                    memcpy(dotpos2, decimalsign, newlength);
                }
            }
        }

        /* this was at the end of every single case, before: */
        dest += strlen(dest);
        ++format;
    } /* for ever */

done:

#if (0)
    /* Oct 2013 - Not safe because it fails to recognize LaTeX macros.	*/
    /* For LaTeX terminals, if the user has not already provided a   	*/
    /* format in math mode, wrap whatever we got by default in $...$ 	*/
    if (((term->flags & TERM_IS_LATEX)) && !strchr(tempdest, '$')) {
        *(outstring++) = '$';
        strcat(tempdest, "$");
        count -= 2;
    }
#endif

    /* Copy as much as fits */
    safe_strncpy(outstring, tempdest, count);

    reset_numeric_locale();
}
コード例 #2
0
ファイル: util.c プロジェクト: lueckenhoff/gnuplot-current
/* HBB 20010121: added code to maintain consistency between mantissa
 * and exponent across sprintf() calls.  The problem: format string
 * '%t*10^%T' will display 9.99 as '10.0*10^0', but 10.01 as
 * '1.0*10^1'.  This causes problems for people using the %T part,
 * only, with logscaled axes, in combination with the occasional
 * round-off error. */
void
gprintf(
    char *dest,
    size_t count,
    char *format,
    double log10_base,
    double x)
{
    char temp[MAX_LINE_LEN + 1];
    char *t;
    TBOOLEAN seen_mantissa = FALSE; /* memorize if mantissa has been
                                       output, already */
    int stored_power = 0;	/* power that matches the mantissa
                                   output earlier */

    set_numeric_locale();

    for (;;) {
	/*{{{  copy to dest until % */
	while (*format != '%')
	    if (!(*dest++ = *format++)) {
		reset_numeric_locale();
		return;		/* end of format */
	    }
	/*}}} */

	/*{{{  check for %% */
	if (format[1] == '%') {
	    *dest++ = '%';
	    format += 2;
	    continue;
	}
	/*}}} */

	/*{{{  copy format part to temp, excluding conversion character */
	t = temp;
	*t++ = '%';
	/* dont put isdigit first since sideeffect in macro is bad */
	while (*++format == '.' || isdigit((unsigned char) *format)
	       || *format == '-' || *format == '+' || *format == ' '
	       || *format == '\'')
	    *t++ = *format;
	/*}}} */

	/*{{{  convert conversion character */
	switch (*format) {
	    /*{{{  x and o */
	case 'x':
	case 'X':
	case 'o':
	case 'O':
	    t[0] = *format;
	    t[1] = 0;
	    sprintf(dest, temp, (int) x);
	    break;
	    /*}}} */
	    /*{{{  e, f and g */
	case 'e':
	case 'E':
	case 'f':
	case 'F':
	case 'g':
	case 'G':
	    t[0] = *format;
	    t[1] = 0;
	    sprintf(dest, temp, x);
	    break;
	    /*}}} */
	    /*{{{  l --- mantissa to current log base */
	case 'l':
	    {
		double mantissa;

		t[0] = 'f';
		t[1] = 0;
		mant_exp(log10_base, x, FALSE, &mantissa, &stored_power, temp);
		seen_mantissa = TRUE;
		sprintf(dest, temp, mantissa);
		break;
	    }
	    /*}}} */
	    /*{{{  t --- base-10 mantissa */
	case 't':
	    {
		double mantissa;

		t[0] = 'f';
		t[1] = 0;
		mant_exp(1.0, x, FALSE, &mantissa, &stored_power, temp);
		seen_mantissa = TRUE;
		sprintf(dest, temp, mantissa);
		break;
	    }
	    /*}}} */
	    /*{{{  s --- base-1000 / 'scientific' mantissa */
	case 's':
	    {
		double mantissa;

		t[0] = 'f';
		t[1] = 0;
		mant_exp(1.0, x, TRUE, &mantissa, &stored_power, temp);
		seen_mantissa = TRUE;
		sprintf(dest, temp, mantissa);
		break;
	    }
	    /*}}} */
	    /*{{{  L --- power to current log base */
	case 'L':
	    {
		int power;

		t[0] = 'd';
		t[1] = 0;
		if (seen_mantissa)
		    power = stored_power;
		else
		    mant_exp(log10_base, x, FALSE, NULL, &power, "%.0f");
		sprintf(dest, temp, power);
		break;
	    }
	    /*}}} */
	    /*{{{  T --- power of ten */
	case 'T':
	    {
		int power;

		t[0] = 'd';
		t[1] = 0;
		if (seen_mantissa)
		    power = stored_power;
		else
		    mant_exp(1.0, x, FALSE, NULL, &power, "%.0f");
		sprintf(dest, temp, power);
		break;
	    }
	    /*}}} */
	    /*{{{  S --- power of 1000 / 'scientific' */
	case 'S':
	    {
		int power;

		t[0] = 'd';
		t[1] = 0;
		if (seen_mantissa)
		    power = stored_power;
		else
		    mant_exp(1.0, x, TRUE, NULL, &power, "%.0f");
		sprintf(dest, temp, power);
		break;
	    }
	    /*}}} */
	    /*{{{  c --- ISO decimal unit prefix letters */
	case 'c':
	    {
		int power;

		t[0] = 'c';
		t[1] = 0;
		if (seen_mantissa)
		    power = stored_power;
		else
		    mant_exp(1.0, x, TRUE, NULL, &power, "%.0f");

		if (power >= -18 && power <= 18) {
		    /* -18 -> 0, 0 -> 6, +18 -> 12, ... */
		    /* HBB 20010121: avoid division of -ve ints! */
		    power = (power + 18) / 3;
		    sprintf(dest, temp, "afpnum kMGTPE"[power]);
		} else {
		    /* please extend the range ! */
		    /* name  power   name  power
		       -------------------------
		       atto   -18    Exa    18
		       femto  -15    Peta   15
		       pico   -12    Tera   12
		       nano    -9    Giga    9
		       micro   -6    Mega    6
		       milli   -3    kilo    3   */

		    /* for the moment, print e+21 for example */
		    sprintf(dest, "e%+02d", (power - 6) * 3);
		}

		break;
	    }
	    /*}}} */
	    /*{{{  P --- multiple of pi */
	case 'P':
	    {
		t[0] = 'f';
		t[1] = 0;
		sprintf(dest, temp, x / M_PI);
		break;
	    }
	    /*}}} */
	default:
	   reset_numeric_locale();
	   int_error(NO_CARET, "Bad format character");
	} /* switch */
	/*}}} */

    /* change decimal `.' to the actual entry in decimalsign */
	if (decimalsign != NULL) {
	    char *dotpos1 = dest, *dotpos2;
	    size_t newlength = strlen(decimalsign);
	    int dot;

	    /* dot is the default decimalsign we will be replacing */
	    dot = *get_decimal_locale();

	    /* replace every dot by the contents of decimalsign */
	    while ((dotpos2 = strchr(dotpos1,dot)) != NULL) {
		size_t taillength = strlen(dotpos2);

		dotpos1 = dotpos2 + newlength;
		/* test if the new value for dest would be too long */
		if (dotpos1 - dest + taillength > count)
		    int_error(NO_CARET,
			      "format too long due to long decimalsign string");
		/* move tail end of string out of the way */
		memmove(dotpos1, dotpos2 + 1, taillength);
		/* insert decimalsign */
		memcpy(dotpos2, decimalsign, newlength);
	    }
	    /* clear temporary variables for safety */
	    dotpos1=NULL;
	    dotpos2=NULL;
	}

	/* this was at the end of every single case, before: */
	dest += strlen(dest);
	++format;
    } /* for ever */

    reset_numeric_locale();
}
コード例 #3
0
ファイル: util.c プロジェクト: TheApacheCats/gnuplot
/* EAM Nov 2012:
 * Unbelievably, the count parameter has been silently ignored or
 * improperly applied ever since this routine was introduced back
 * in version 3.7.  Now fixed to prevent buffer overflow.
 */
void
gprintf(
    char *outstring,
    size_t count,
    char *format,
    double log10_base,
    double x)
{
    char tempdest[MAX_LINE_LEN + 1];
    char temp[MAX_LINE_LEN + 1];
    char *t;
    TBOOLEAN seen_mantissa = FALSE; /* remember if mantissa was already output */
    double stored_power_base = 0;   /* base for the last mantissa output*/
    int stored_power = 0;	/* power matching the mantissa output earlier */
    TBOOLEAN got_hash = FALSE;				   

    char *dest = &tempdest[0];
    char *limit = &tempdest[MAX_LINE_LEN];
#define remaining_space (size_t)(limit-dest)

    *dest = '\0';

    set_numeric_locale();

    for (;;) {
	/*{{{  copy to dest until % */
	while (*format != '%')
	    if (!(*dest++ = *format++) || (remaining_space == 0)) {
		safe_strncpy(outstring,tempdest,count);
		reset_numeric_locale();
		return;		/* end of format */
	    }
	/*}}} */

	/*{{{  check for %% */
	if (format[1] == '%') {
	    *dest++ = '%';
	    format += 2;
	    continue;
	}
	/*}}} */

	/*{{{  copy format part to temp, excluding conversion character */
	t = temp;
	*t++ = '%';
	if (format[1] == '#') {
	    *t++ = '#';
	    format++;
	    got_hash = TRUE;
	}
	/* dont put isdigit first since sideeffect in macro is bad */
	while (*++format == '.' || isdigit((unsigned char) *format)
	       || *format == '-' || *format == '+' || *format == ' '
	       || *format == '\'')
	    *t++ = *format;
	/*}}} */

	/*{{{  convert conversion character */
	switch (*format) {
	    /*{{{  x and o */
	case 'x':
	case 'X':
	case 'o':
	case 'O':
	    if (fabs(x) >= (double)INT_MAX) {
		t[0] = 'l';
		t[1] = 'l';
		t[2] = *format;
		t[3] = '\0';
		snprintf(dest, remaining_space, temp, (long long) x);
	    } else {
		t[0] = *format;
		t[1] = '\0';
		snprintf(dest, remaining_space, temp, (int) x);
	    }
	    break;
	    /*}}} */
	    /*{{{  e, f and g */
	case 'e':
	case 'E':
	case 'f':
	case 'F':
	case 'g':
	case 'G':
	    t[0] = *format;
	    t[1] = 0;
	    snprintf(dest, remaining_space, temp, x);
	    break;
	    /*}}} */
	    /*{{{  l --- mantissa to current log base */
	case 'l':
	    {
		double mantissa;

		t[0] = 'f';
		t[1] = 0;
		stored_power_base = log10_base;
		mant_exp(stored_power_base, x, FALSE, &mantissa,
				&stored_power, temp);
		seen_mantissa = TRUE;
		snprintf(dest, remaining_space, temp, mantissa);
		break;
	    }
	    /*}}} */
	    /*{{{  t --- base-10 mantissa */
	case 't':
	    {
		double mantissa;

		t[0] = 'f';
		t[1] = 0;
		stored_power_base = 1.0;
		mant_exp(stored_power_base, x, FALSE, &mantissa,
				&stored_power, temp);
		seen_mantissa = TRUE;
		snprintf(dest, remaining_space, temp, mantissa);
		break;
	    }
	    /*}}} */
	    /*{{{  s --- base-1000 / 'scientific' mantissa */
	case 's':
	    {
		double mantissa;

		t[0] = 'f';
		t[1] = 0;
		stored_power_base = 1.0;
		mant_exp(stored_power_base, x, TRUE, &mantissa,
				&stored_power, temp);
		seen_mantissa = TRUE;
		snprintf(dest, remaining_space, temp, mantissa);
		break;
	    }
	    /*}}} */
	    /*{{{  b --- base-1024 mantissa */
	case 'b':
	    {
		double mantissa;

		t[0] = 'f';
		t[1] = 0;
		stored_power_base = log10(1024);
		mant_exp(stored_power_base, x, FALSE, &mantissa,
				&stored_power, temp);
		seen_mantissa = TRUE;
		snprintf(dest, remaining_space, temp, mantissa);
		break;
	    }
	    /*}}} */
	    /*{{{  L --- power to current log base */
	case 'L':
	    {
		int power;

		t[0] = 'd';
		t[1] = 0;
		if (seen_mantissa)
		    if (stored_power_base == log10_base)
			power = stored_power;
		    else
			int_error(NO_CARET, "Format character mismatch: %%L is only valid with %%l");
		else
		    stored_power_base = log10_base;
		    mant_exp(log10_base, x, FALSE, NULL, &power, "%.0f");
		snprintf(dest, remaining_space, temp, power);
		break;
	    }
	    /*}}} */
	    /*{{{  T --- power of ten */
	case 'T':
	    {
		int power;

		t[0] = 'd';
		t[1] = 0;
		if (seen_mantissa)
		    if (stored_power_base == 1.0)
			power = stored_power;
		    else
			int_error(NO_CARET, "Format character mismatch: %%T is only valid with %%t");
		else
		    mant_exp(1.0, x, FALSE, NULL, &power, "%.0f");
		snprintf(dest, remaining_space, temp, power);
		break;
	    }
	    /*}}} */
	    /*{{{  S --- power of 1000 / 'scientific' */
	case 'S':
	    {
		int power;

		t[0] = 'd';
		t[1] = 0;
		if (seen_mantissa)
		    if (stored_power_base == 1.0)
			power = stored_power;
		    else
			int_error(NO_CARET, "Format character mismatch: %%S is only valid with %%s");
		else
		    mant_exp(1.0, x, TRUE, NULL, &power, "%.0f");
		snprintf(dest, remaining_space, temp, power);
		break;
	    }
	    /*}}} */
	    /*{{{  c --- ISO decimal unit prefix letters */
	case 'c':
	    {
		int power;

		t[0] = 'c';
		t[1] = 0;
		if (seen_mantissa)
		    if (stored_power_base == 1.0)
			power = stored_power;
		    else
			int_error(NO_CARET, "Format character mismatch: %%c is only valid with %%s");
		else
		    mant_exp(1.0, x, TRUE, NULL, &power, "%.0f");

		if (power >= -24 && power <= 24) {
		    /* -18 -> 0, 0 -> 6, +18 -> 12, ... */
		    /* HBB 20010121: avoid division of -ve ints! */
		    power = (power + 24) / 3;
		    snprintf(dest, remaining_space, temp, "yzafpnum kMGTPEZY"[power]);
		} else {
		    /* please extend the range ! */
		    /* name  power   name  power
		       -------------------------
		       yocto  -24    yotta  24
		       zepto  -21    zetta  21
		       atto   -18    Exa    18
		       femto  -15    Peta   15
		       pico   -12    Tera   12
		       nano    -9    Giga    9
		       micro   -6    Mega    6
		       milli   -3    kilo    3   */

		    /* fall back to simple exponential */
		    snprintf(dest, remaining_space, "e%+02d", power);
		}
		break;
	    }
	    /*}}} */
	    /*{{{  B --- IEC 60027-2 A.2 / ISO/IEC 80000 binary unit prefix letters */
	case 'B':
	    {
		int power;

		t[0] = 'c';
		t[1] = 'i';
		t[2] = 0;
		if (seen_mantissa)
		    if (stored_power_base == log10(1024))
			power = stored_power;
		    else
			int_error(NO_CARET, "Format character mismatch: %%B is only valid with %%b");
		else
			mant_exp(log10(1024), x, FALSE, NULL, &power, "%.0f");

		if (power > 0 && power <= 8) {
		    /* name  power
		       -----------
		       Yobi   8
		       Zebi   7
		       Exbi   9
		       Pebi   5
		       Tebi   4
		       Gibi   3
		       Mebi   2
		       kibi   1   */
		    snprintf(dest, remaining_space, temp, " kMGTPEZY"[power]);
		} else if (power > 8) {
		    /* for the larger values, print x2^{10}Gi for example */
		    snprintf(dest, remaining_space, "x2^{%d}Yi", power-8);
		} else if (power < 0) {
		    snprintf(dest, remaining_space, "x2^{%d}", power*10);
		}

		break;
	    }
	    /*}}} */
	    /*{{{  P --- multiple of pi */
	case 'P':
	    {
		t[0] = 'f';
		t[1] = 0;
		snprintf(dest, remaining_space, temp, x / M_PI);
		break;
	    }
	    /*}}} */
	default:
	   reset_numeric_locale();
	   int_error(NO_CARET, "Bad format character");
	} /* switch */
	/*}}} */
	
	if (got_hash && (format != strpbrk(format,"oeEfFgG"))) {
	   reset_numeric_locale();
	   int_error(NO_CARET, "Bad format character");
	}

    /* change decimal `.' to the actual entry in decimalsign */
	if (decimalsign != NULL) {
	    char *dotpos1 = dest, *dotpos2;
	    size_t newlength = strlen(decimalsign);
	    int dot;

	    /* dot is the default decimalsign we will be replacing */
	    dot = *get_decimal_locale();

	    /* replace every dot by the contents of decimalsign */
	    while ((dotpos2 = strchr(dotpos1,dot)) != NULL) {
		size_t taillength = strlen(dotpos2);

		dotpos1 = dotpos2 + newlength;
		/* test if the new value for dest would be too long */
		if (dotpos1 - dest + taillength > count)
		    int_error(NO_CARET,
			      "format too long due to long decimalsign string");
		/* move tail end of string out of the way */
		memmove(dotpos1, dotpos2 + 1, taillength);
		/* insert decimalsign */
		memcpy(dotpos2, decimalsign, newlength);
	    }
	    /* clear temporary variables for safety */
	    dotpos1=NULL;
	    dotpos2=NULL;
	}

	/* this was at the end of every single case, before: */
	dest += strlen(dest);
	++format;
    } /* for ever */

    /* Copy as much as fits */
    safe_strncpy(outstring, tempdest, count);

    reset_numeric_locale();
}