home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************
- Source file: INFLOAT.C
-
- INCON floating-point input handler.
-
- Compiler: Borland Turbo C 2.01
-
- INCON source files and the object and library files created from
- them are:
- Copyright (c) 1993-94, Richard Zigler.
- You may freely distribute unmodified source, object, and library
- files, and incorporate them into your own non-commercial software,
- provided that this paragraph and the program name and copyright
- strings defined in INCON.C are included in all copies.
- *************************************************************************/
-
- #include <ctype.h> /* character classification */
- #include <string.h>
- #include "indefs.h" /* globals and definitions */
- #include "incon.h" /* state definitions */
- #include "indecl.h" /* public utility routines */
-
- /**** Local Data ****/
-
- enum /* float field fix-up constants */
- {
- FLT_INIT , /* initialize field for display */
- FLT_FIX , /* fix field left of decimal */
- FLT_MOV , /* move chars left of decimal */
- FLT_PAD , /* pad out field with zeros */
- } ;
-
- static BFLAG Point ; /* decimal point entered yet? */
- static short PointNdx ; /* decimal point index */
- static BFLAG Sign ; /* sign entered yet? */
- static short SignNdx ; /* numeric sign index */
-
- /**** Local Routines ****/
-
- static int near pascal FloatFix
- (
- int Op, /* operation requested */
- int Pos /* index into string */
- ) ;
-
- int pascal hFloatField( STATES State, register int Pos )
- {
- register int max_width = Width - 1;
- int old_pos = Pos;
-
- switch( State )
- {
- case stError:
- break;
-
- case stQuit: /* [Enter] -- end input */
- Chr = 0;
- goto __FloatExit;
-
- case stInit: /* field initialization */
- SignNdx = 0;
- Point = Sign = NO;
- StrLength = Width;
- if ( !Prec )
- {
- Prec = strchr( OutStr, '.' ) - OutStr;
- Prec = StrLength - Prec - 1;
- }
- PointNdx = Width - Prec - 1;
- if ( !PointNdx )
- {
- --Prec; /* force at least one decimal */
- ++PointNdx; /* digit position */
- }
- if ( PointNdx > 0 )
- {
- Flags.Confirm =
- Flags.Display = YES;
- Pos = FloatFix( FLT_INIT, 0 );
- }
- return ( Pos );
-
- case stFieldClear: /* [Esc] -- clear field or exit */
- if ( EscSet)
- More = NO;
- else
- {
- memset( OutStr, Fill, Width );
- OutStr[PointNdx] = '.';
- Pos =
- SignNdx =
- Sign = 0;
- ++Update;
- }
- break;
-
- case stDeleteCharLeft: /* [Backspace] -- delete left */
- if ( Pos )
- {
- --Move;
- if ( Pos == max_width && OutStr[Pos] != (char)Fill )
- OutStr[Pos] = Fill;
- else if ( --Pos == PointNdx )
- OutStr[--Pos] = Fill;
- else
- {
- if ( Pos < PointNdx )
- max_width = PointNdx - 1;
- goto __MoveCharsToCursor;
- }
- }
- break;
-
- case stMoveToStart: /* [Home] -- start of field */
- if ( Pos )
- {
- Pos = 0;
- --Move;
- }
- break;
-
- case stMoveCharLeft: /* [Left Arrow] -- move char lt */
- if ( Pos )
- {
- if ( --Pos <= SignNdx )
- Pos = 0;
- --Move;
- }
- break;
-
- case stMoveCharRight: /* [Right Arrow] -- move char rt */
- if ( Pos < max_width )
- {
- ++Pos;
- ++Move;
- }
- break;
-
- case stMoveToEnd: /* [End] -- end of field */
- if ( Pos < max_width )
- {
- Pos = max_width;
- ++Move;
- }
- break;
-
- case stMoveWordLeft: /* [Ctrl Left] -- move word lt */
- if ( Pos )
- {
- Pos = Pos > PointNdx + 1 ? PointNdx + 1 : 0 ;
- --Move;
- }
- break;
-
- case stMoveWordRight: /* [Ctrl Right] -- move word rt */
- if ( Pos < max_width )
- {
- Pos = Pos < PointNdx ? PointNdx + 1 : max_width ;
- ++Move;
- }
- break;
-
- case stDeleteWordLeft: /* [Ctrl L] -- delete word left */
- if ( Pos == (PointNdx + 1) )
- Pos = PointNdx - 1;
- max_width = Pos;
- Pos = Pos > PointNdx ? PointNdx + 1 : 0 ;
- goto __DeleteWord;
-
- case stDeleteWordRight: /* [Ctrl R] -- delete word right */
- if ( Pos == (PointNdx - 1) )
- Pos = PointNdx + 1;
- if ( Pos < PointNdx )
- max_width = PointNdx - 1; /* fall through to __DeleteWord */
-
- case stDeleteToEnd: /* [Ctrl End] -- clear to end */
-
- __DeleteWord:
- ;
- memset( OutStr + Pos, Fill, max_width - Pos + 1 );
- OutStr[PointNdx] = '.';
- ++Update;
- break;
-
- case stDeleteToStart: /* [Ctrl Home] -- clear to start */
- max_width = Pos;
- Pos = 0;
- goto __DeleteWord;
-
- case stDeleteAtCursor: /* [Del] -- delete at cursor */
- if ( Pos < PointNdx )
- max_width = PointNdx - 1;
- ++Update;
-
- __MoveCharsToCursor:
- ;
- memcpy( OutStr + Pos, OutStr + Pos + 1, max_width - Pos );
- OutStr[max_width] = Fill;
- break;
-
- case stExitPlus: /* [Keypad +] -- special exit */
- case stExitMinus: /* [Keypad -] -- special exit */
-
- /****
- If cursor is to right of sign position or Sign flag
- is off, treat these keys as exits; otherwise convert
- Chr to '+' or '-' and fall through to stCharMatch.
- ****/
-
- if ( Pos > SignNdx || !Flags.Sign )
- {
-
- __FloatExit:
- ;
- FloatFix( FLT_FIX, PointNdx );
- FloatFix( FLT_PAD, 0 );
- More = NO;
- ++Update;
- break;
- }
- else
- Chr = (State == stExitPlus) ? '+' : '-' ;
-
- case stCharMatch: /* see if entry matches field */
- if
- (
- isdigit( Chr )
- ||
- ( (Chr == '+' || Chr == '-') && Pos <= SignNdx && Flags.Sign )
- ||
- ( !Point && Chr == '.' )
- )
- {
- if ( InBegin )
- Pos = hFloatField( stFieldClear, 0 );
- if ( Chr == '+' || Chr == '-' )
- {
- Sign = Chr;
- SignNdx = Pos;
- }
- if ( Chr == '.' )
- {
- FloatFix( FLT_FIX, Pos );
- Pos = PointNdx + 1;
- memset( OutStr + Pos, Fill, Prec );
- }
- else
- OutStr[Pos++] = Chr;
- ++Move;
- } /* if (isdigit) */
- else
- State = stError;
- break;
- } /* switch */
-
- if ( Pos >= Width )
- Pos = Width - 1;
- if ( Pos == PointNdx )
- Pos += Move; /* move left or right past sign */
- Point = (Pos >= PointNdx);
-
- if ( Move )
- {
-
- /****
- If the cursor has passed to the left of the sign (or
- implied sign) position, FloatFix() moves the integer
- portion of OutStr to the beginning of the field and
- fills vacant digit positions with Fill.
- ****/
-
- if ( Pos <= SignNdx )
- Pos = FloatFix( FLT_MOV, PointNdx );
-
- /****
- If the cursor has passed to the right over the decimal
- point, FloatFix() closes gaps in the integer portion of
- OutStr and moves that part of the string adjacent to the
- point. After the call to FloatFix(), all fill characters
- to the left of the decimal point have been replaced by
- digits, sign, or spaces, so FloatFix() is not called on
- subsequent moves while the cursor is still to the right
- of the decimal.
- ****/
-
- if ( Move > 0 && Pos > PointNdx )
- {
- if ( memchr( OutStr, Fill, PointNdx ) )
- FloatFix( FLT_FIX, PointNdx );
- }
-
- /****
- If the cursor has passed to the left over the decimal
- point, FloatFix() closes gaps in the decimal portion
- of OutStr and pads it with zeros. After the call to
- FloatFix(), all fill characters to the right of the
- decimal point have been replaced by digits, so
- FloatFix() is not called on subsequent moves while
- the cursor is still to the left of the decimal.
- ****/
-
- else if ( Move < 0 && Pos < PointNdx && old_pos > PointNdx )
- {
- if ( memchr( OutStr + PointNdx + 1, Fill, Prec ) )
- FloatFix( FLT_PAD, PointNdx );
- }
- ++Update;
- Move = NO;
- } /* if(Move) */
- return( Pos );
- } /**** hFloatField() ****/
-
- /*************************************************************************
- FloatFix()
- Patches up the output string in floating-point fields.
- *************************************************************************/
-
- static int near pascal FloatFix
- (
- int Op, /* operation requested */
- register int Pos /* index into string */
- )
- {
- BYTE chr; /* char from input string */
- register int s_ptr; /* alternate index */
- int work; /* integer working storage */
-
- switch ( Op )
- {
- case FLT_INIT:
-
- memset( OutStr, Fill, Width );
- OutStr[PointNdx] = '.';
- SignNdx =
- Sign = 0;
-
- /****
- If the default input string is not to be displayed in
- the input field then initialization is complete. If
- it is to be displayed, each character must be examined
- and put in its proper place, since the string may not
- be formatted like the field.
- ****/
-
- if ( !Flags.Display )
- break;
- else
- {
- for ( Pos = 0 ; Pos <= PointNdx ; Pos++ )
- {
- chr = InStr[Pos]; /* get char from default string */
-
- /****
- If the integer portion of OutStr has been filled
- but the default string decimal point hasn't been
- found, use work to index the decimal portion of
- the default string. Advance work beyond the
- default string decimal point, discarding any
- remaining integer digits in the default string.
- ****/
-
- if ( Pos == PointNdx )
- {
- work = Pos;
- do
- chr = InStr[work++];
- while ( chr && chr != '.' );
- }
-
- else if ( isdigit( chr ) ) /* copy digits to OutStr */
- OutStr[Pos] = chr;
-
- /****
- If a sign character is found in the integer
- portion of the default string, force signed
- input and set the index and flags accordingly.
- No attempt is made here to make sense of some
- such string as "+12-34.56". The last sign in
- the default string determines the ultimate
- setting of index and flags; any characters
- preceding that will be discarded at FLT_FIX.
- ****/
-
- else if ( chr == '+' || chr == '-' )
- {
- Flags.Sign = YES;
- SignNdx = Pos;
- Sign =
- OutStr[Pos] = chr;
- }
-
- /****
- Pos is still in the integer portion of OutStr
- but a decimal or the end-of-string null has
- been found in the default string. Move Pos
- to the decimal point in OutStr so that for()
- fails. Pos will be incremented at the bottom
- of the for loop prior to exit, so it will wind
- up pointing at the position following the decimal
- point in OutStr. Use work to index the remaining
- digits of the default string, if any.
- ****/
-
- else if ( !chr || chr == '.' )
- {
- work = Pos + 1;
- Pos = PointNdx;
- }
- } /* for (Pos) */
-
- /*******************************************************
- At this point, for() has failed for one of
- three reasons: encountered the end of the
- default string; found the default string
- decimal; or reached the decimal position
- in OutStr. In the first case, the while()
- test below will fail immediately. The two
- remaining cases are illustrated here. Pos
- and work are shown as they have been set
- above; 'd' represents a decimal integer.
- --------------------------------------------------------
- Found the default string decimal:
-
- default: 1 2 3 . 4 5
- work __/
-
- OutStr: 1 2 3 d . d d d d
- Pos __/
-
- OutStr will be adjusted at FLT_FIX.
- --------------------------------------------------------
- Reached the decimal point in OutStr:
-
- default: 1 2 3 4 5 . 6 7
- work __/
-
- OutStr: 1 2 3 4 . d d d d
- Pos __/
-
- The extra integer digit in the default string
- is discarded.
- *******************************************************/
-
- /****
- Copy digits from default to OutStr until either
- OutStr is filled or the end of the default string
- is reached. Any non-digit characters that may be
- lurking in the default string are discarded. At
- this point, chr will contain either the default
- string decimal point or end-of-string null.
- ****/
-
- while ( chr && Pos < Width )
- {
- if ( isdigit( chr ) )
- OutStr[Pos++] = chr;
- chr = InStr[work++];
- }
-
- /****
- Now fall through to FLT_FIX to prettify the output
- string for display.
- ****/
-
- } /* if(Flags.Display) */
-
- case FLT_FIX :
-
- /****
- Move the integer portion of OutStr adjacent to the
- decimal point. Pad the beginning of the string with
- spaces.
- ****/
-
- s_ptr = PointNdx;
- if ( Pos > s_ptr )
- Pos = s_ptr;
-
- while ( Pos )
- {
- chr = OutStr[--Pos];
-
- /****
- Copy digits to s_ptr. Pos is decremented with each
- pass through the loop but s_ptr is decremented only
- when a valid character is found, so it indexes the
- decimal until the first character is copied.
- ****/
-
- if ( isdigit( chr ) )
- OutStr[--s_ptr] = chr;
-
- /****
- Copy sign to s_ptr. If s_ptr has not moved from the
- decimal there are no digits between the decimal and
- the sign. If there is room for it, insert a zero
- between the sign and the decimal point and mark the
- new position of the sign.
- ****/
-
- else if ( chr == Sign && Pos == SignNdx )
- {
- if ( s_ptr == PointNdx && s_ptr > 1 )
- OutStr[--s_ptr] = '0';
- OutStr[--s_ptr] = chr;
- SignNdx = s_ptr;
- break;
- }
- } /* while (Pos) */
-
- if ( s_ptr == PointNdx && s_ptr > 0 ) /* if no digits/sign, */
- OutStr[--s_ptr] = '0'; /* insert 0 if possible */
- for ( Pos = 0 ; Pos < s_ptr ; Pos++ ) /* blank shifted sign */
- OutStr[Pos] = ' '; /* and digits */
- if ( SignNdx < s_ptr ) /* index the sign or */
- SignNdx = s_ptr; /* the implied sign */
- break;
-
- case FLT_MOV :
-
- /****
- Move the integer portion of OutStr to the beginning
- of the input field.
- ****/
-
- Pos = PointNdx - SignNdx;
- if ( Pos > 0 )
- {
- memcpy( OutStr, OutStr + SignNdx, Pos );
- memset( OutStr + Pos, Fill, SignNdx );
- }
- Pos = SignNdx = 0;
- break;
-
- case FLT_PAD :
-
- /****
- Close gaps between digits in the decimal portion of
- OutStr and pad the end of the string with zeros.
- ****/
-
- Pos = s_ptr = PointNdx + 1;
- while ( Pos < Width )
- {
- chr = OutStr[Pos++];
- if ( isdigit( chr ) )
- OutStr[s_ptr++] = chr;
- }
- while ( s_ptr < Width )
- OutStr[s_ptr++] = '0';
- break;
- } /* switch (Op) */
- return( Pos );
- } /**** FloatFix() ****/
-
- /**** EOF: INFLOAT.C ****/