fmtcnvt.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 346 行
C
346 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
//
// FMTCNVT : integer and floating point conversion routines
//
#include "ftnstd.h"
#include "intcnv.h"
#include "fltcnv.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <float.h>
extern bool MulIOFlo(intstar4 *,intstar4 *);
extern bool AddIOFlo(intstar4 *,intstar4 *);
int FmtS2I( char *str, int len, bool blanks, intstar4 *value, bool stop_ok,
int *width ) {
//============================
// Convert a FORTRAN I format string to an integer.
char ch;
bool sign;
char *strend;
bool minus;
int status;
int wid;
intstar4 result;
intstar4 tmp;
status = INT_OK;
strend = str + len;
for(;;) {
if( *str != ' ' ) break;
str++;
if( str == strend ) break;
}
minus = FALSE;
sign = FALSE;
if( str != strend ) {
ch = *str;
if( (ch == '+') || (ch == '-') ) {
if( ch == '-' ) {
minus = TRUE;
}
str++;
sign = TRUE;
}
}
result = 0;
for( ; str != strend; str++ ) {
ch = *str;
if( ch == ' ' ) {
if( !blanks ) continue;
ch = '0';
}
if( isdigit( ch ) == 0 ) break;
tmp = 10;
if( MulIOFlo( &result, &tmp ) ) {
status = INT_OVERFLOW;
}
tmp = ch - '0';
if( minus ) {
tmp = -tmp;
}
if( AddIOFlo( &result, &tmp ) ) {
status = INT_OVERFLOW;
}
sign = FALSE;
}
if( sign ) {
str = NULL;
} else {
*value = result;
}
wid = len;
if( str != strend ) {
if( stop_ok && !sign ) {
wid -= ( strend - str );
} else {
status = INT_INVALID;
}
}
if( width != NULL ) {
*width = wid;
}
return( status );
}
int FmtS2F( char *field, int width, int decimals, bool blanks,
int scale, int prec, extended *result, bool stop_ok,
int *new_width, bool extend_flt ) {
//=================================================
// Format a string to floating point representation.
char *stop;
char ch;
char *start;
canon_form canon;
intstar4 exp;
// initialize the canonical form of the number to be collected
canon.exp = 0;
canon.neg = FALSE;
canon.col = 0;
canon.flags = 0;
canon.blanks = 0;
// scan over blanks
stop = field + width;
for(;;) {
if( *field != ' ' ) break;
field++;
if( field == stop ) break;
}
start = field;
// process optional sign
if( field != stop ) {
ch = *field;
if( (ch == '-') || (ch == '+') ) {
canon.flags |= FOUND_SIGN;
field++;
start++;
if( ch != '+' ) {
canon.neg = TRUE;
}
}
}
// collect digits on left of decimal
memset( _CanonDigits( &canon ), '0', CONVERSION_DIGITS );
_CanonDigits( &canon )[CONVERSION_DIGITS] = NULLCHAR;
field += Digits( &canon, field, stop, decimals, blanks, LEFT_DIGITS );
// collect optional decimal point
if( (field != stop) && (*field == '.') ) {
canon.exp = canon.col;
field++;
canon.flags |= DECIMAL;
}
// collect digits on right of decimal
field += Digits( &canon, field, stop, decimals, blanks, RIGHT_DIGITS );
// collect optional exponent
if( field != stop ) {
ch = tolower( *field );
if( (ch == 'e') || (ch == 'd') || (ch == 'q') || (ch == '+') ||
(ch == '-') ) {
if( ( ch == 'e' ) && extend_flt ) {
canon.flags |= DOUBLE;
} else if( ch == 'd' ) {
if( extend_flt ) {
canon.flags |= LONGDOUBLE;
} else {
canon.flags |= DOUBLE;
}
} else if( ch == 'q' ) {
canon.flags |= LONGDOUBLE;
}
// if E|D found but no decimal, use the specified # of decimals
if( !(canon.flags & DECIMAL) ) {
canon.exp = canon.col - decimals + canon.blanks;
}
if( ch != '-' ) {
field++;
}
canon.flags |= EXPONENT;
if( (stop == field) ||
(FmtS2I( field, stop - field, blanks, &exp, FALSE, NULL )
!= INT_OK) ) {
canon.flags |= BAD_EXPONENT;
}
canon.exp += exp;
field = stop;
}
}
// if exponent was found, override the scale factor
if( canon.flags & EXPONENT ) {
canon.exp += scale;
}
if( new_width ) {
*new_width = width - ( stop - field );
}
if( !stop_ok && ( field != stop ) ) return( FLT_INVALID );
if( canon.flags & BAD_EXPONENT ) return( FLT_INVALID );
if( (canon.flags & (FOUND_SIGN | DECIMAL | EXPONENT)) &&
!(canon.flags & (LEFT_DIGITS|RIGHT_DIGITS)) ) return( FLT_INVALID );
canon.exp -= scale; // adjust for kP specifier
if( !(canon.flags & DECIMAL) ) { // if no '.' found
// adjust for BN specifier
canon.exp -= canon.blanks;
}
// Convert the string to floating-point
if( canon.neg ) {
*_CanonSign( &canon ) = '-';
} else {
*_CanonSign( &canon ) = ' ';
}
*_CanonDecimal( &canon ) = '.';
*_CanonExponent( &canon ) = 'E';
itoa( canon.exp, &_CanonExponent( &canon )[1], 10 );
errno = 0;
*result = strtod( _CanonNumber( &canon ), NULL );
if( errno != 0 ) return( FLT_RANGE_EXCEEDED );
if( prec == PRECISION_SINGLE ) {
if( !(canon.flags & DOUBLE) && !( canon.flags & LONGDOUBLE ) ) {
single volatile sresult;
if( *result > FLT_MAX ) return( FLT_RANGE_EXCEEDED );
sresult = *result;
*result = sresult;
}
} else if( prec == PRECISION_DOUBLE ) {
if( !(canon.flags & LONGDOUBLE) ) {
double volatile sresult;
if( *result > DBL_MAX ) return( FLT_RANGE_EXCEEDED );
sresult = *result;
*result = sresult;
}
}
return( FLT_OK );
}
static int Digits( canon_form *canon, char *field, char *stop,
int decimals, bool blanks, byte flag ) {
//==============================================================
// Collect digits to the left or right of the decimal point. Take blanks
// into consideration. Set "canon->exp" accordingly.
int count;
char ch;
count = 0;
for(;;) {
for(;;) {
if( field == stop ) break;
ch = *field;
if( ch != ' ' ) break;
if( blanks ) {
ch = '0';
} else {
if( flag == LEFT_DIGITS ) {
canon->blanks++;
}
++field;
++count;
}
if( ch == '0' ) break;
}
if( field == stop ) break;
if( isdigit( ch ) == 0 ) break;
if( canon->col == 0 ) {
if( ch == '0' ) {
if( canon->flags & DECIMAL ) {
canon->exp--;
}
} else {
if( !(canon->flags & DECIMAL) ) {
canon->exp = stop - field - decimals;
}
AddDig( canon, ch );
}
} else {
AddDig( canon, ch );
}
count++;
field++;
}
if( count > 0 ) {
canon->flags |= flag;
}
return( count );
}
static void AddDig( canon_form *canon, char ch ) {
//====================================================
// Add a significant digit to mantissa.
int col;
col = canon->col;
canon->col++;
if( col <= CONVERSION_DIGITS ) {
_CanonDigits( canon )[col] = ch;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?