| /* Implement Input/Output runtime actions for CHILL. |
| Copyright (C) 1992,1993 Free Software Foundation, Inc. |
| Author: Wilfried Moser, et al |
| |
| This file is part of GNU CC. |
| |
| GNU CC 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 2, or (at your option) |
| any later version. |
| |
| GNU CC 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 GNU CC; see the file COPYING. If not, write to |
| the Free Software Foundation, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. */ |
| |
| /* As a special exception, if you link this library with other files, |
| some of which are compiled with GCC, to produce an executable, |
| this library does not by itself cause the resulting executable |
| to be covered by the GNU General Public License. |
| This exception does not however invalidate any other reasons why |
| the executable file might be covered by the GNU General Public License. */ |
| |
| #include <limits.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <setjmp.h> |
| #include <float.h> |
| #include <math.h> |
| #include <stdlib.h> |
| #if _TEXTIO_DEBUG_ |
| #include <stdio.h> |
| #endif |
| |
| #include "bitstring.h" |
| #include "auxtypes.h" |
| #include "iomodes.h" |
| #include "format.h" |
| #include "fileio.h" |
| #include "ioerror.h" |
| |
| #define CH_BYTE_MIN 0xffffff80L |
| #define CH_BYTE_MAX 0x0000007fL |
| #define CH_UBYTE_MAX 0x000000ffUL |
| #define CH_INT_MIN 0xffff8000L |
| #define CH_INT_MAX 0x00007fffL |
| #define CH_UINT_MAX 0x0000ffffUL |
| #define CH_LONG_MIN 0x80000000L |
| #define CH_LONG_MAX 0x7fffffffL |
| #define CH_ULONG_MAX 0xffffffffUL |
| |
| #ifndef M_LN2 |
| #define M_LN2 0.69314718055994530942 |
| #endif |
| #ifndef M_LN10 |
| #define M_LN10 2.30258509299404568402 |
| #endif |
| |
| #define DMANTDIGS (1 + (int)(DBL_MANT_DIG * M_LN2 / M_LN10)) |
| #define FMANTDIGS (1 + (int)(FLT_MANT_DIG * M_LN2 / M_LN10)) |
| |
| /* float register length */ |
| #define MAXPREC 40 |
| |
| #define LET 0x0001 |
| #define BIN 0x0002 |
| #define DEC 0x0004 |
| #define OCT 0x0008 |
| #define HEX 0x0010 |
| #define USC 0x0020 |
| #define BIL 0x0040 |
| #define SPC 0x0080 |
| #define SCS 0x0100 |
| #define IOC 0x0200 |
| #define EDC 0x0400 |
| #define CVC 0x0800 |
| |
| #define isDEC(c) ( chartab[(c)] & DEC ) |
| #define isCVC(c) ( chartab[(c)] & CVC ) |
| #define isEDC(c) ( chartab[(c)] & EDC ) |
| #define isIOC(c) ( chartab[(c)] & IOC ) |
| #define isUSC(c) |
| #define isXXX(c,XXX) ( chartab[(c)] & XXX ) |
| |
| /* |
| * local definitions |
| */ |
| |
| static |
| short int chartab[256] = { |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, SPC, SPC, SPC, SPC, SPC, 0, 0, |
| |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| |
| SPC, IOC, 0, 0, 0, 0, 0, 0, |
| SCS, SCS, SCS, SCS+IOC, SCS, SCS+IOC, SCS, SCS+IOC, |
| BIN+OCT+DEC+HEX, BIN+OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX, |
| OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX, |
| DEC+HEX, DEC+HEX, SCS, SCS, SCS+EDC, SCS+IOC, SCS+EDC, IOC, |
| |
| 0, LET+HEX+BIL, LET+HEX+BIL+CVC, LET+HEX+BIL+CVC, LET+HEX+BIL, LET+HEX, |
| LET+HEX+CVC, LET, |
| LET+BIL+CVC, LET, LET, LET, LET, LET, LET, LET+CVC, |
| |
| LET, LET, LET, LET, LET+EDC, LET, LET, LET, |
| LET+EDC, LET, LET, SCS, 0, SCS, 0, USC, |
| |
| 0, LET+HEX, LET+HEX, LET+HEX, LET+HEX, LET+HEX, LET+HEX, LET, |
| LET, LET, LET, LET, LET, LET, LET, LET, |
| |
| LET, LET, LET, LET, LET, LET, LET, LET, |
| LET, LET, LET, 0, 0, 0, 0, 0 |
| }; |
| |
| typedef enum { |
| FormatText, FirstPercent, RepFact, ConvClause, EditClause, ClauseEnd, |
| AfterWidth, FractWidth, FractWidthCont, ExpoWidth, ExpoWidthCont, |
| ClauseWidth, CatchPadding, LastPercent |
| } fcsstate_t; |
| |
| #define CONVERSIONCODES "CHOBF" |
| typedef enum { |
| DefaultConv, HexConv, OctalConv, BinaryConv, ScientConv |
| } convcode_t; |
| |
| static |
| short int base[4] = { 10, 16, 8, 2 }; |
| |
| static |
| short int dset[4] = { DEC, HEX, OCT, BIN }; |
| |
| #define EDITCODES "X<>T" |
| typedef enum { |
| SpaceSkip, SkipLeft, SkipRight, Tabulation |
| } editcode_t; |
| |
| #define IOCODES "/+-?!=" |
| typedef enum { |
| NextRecord, NextPage, CurrentLine, Prompt, Emit, EndPage |
| } iocode_t; |
| |
| typedef enum { |
| ConvAct, EditAct, IOAct |
| } acttype_t; |
| |
| typedef enum { |
| NormalEnd, EndAtParen, TextFailEnd |
| } formatexit_t; |
| |
| static |
| double ep_1[10] = { |
| 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 }; |
| static |
| double ep_10[10] = { |
| 1e0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 }; |
| static |
| double ep_100 = 1e100; |
| |
| /* float register */ |
| static |
| unsigned char floatdig[MAXPREC]; |
| |
| /* |
| * global io variables |
| */ |
| |
| static Text_Mode* textptr = NULL; |
| static VarString* textrecptr; |
| |
| static int actual_index; |
| static int maximum_index; |
| static int iolist_index; |
| |
| static __tmp_IO_list* iolistptr; |
| static int iolistlen; |
| static char* iostrptr; |
| static int iostrlen; |
| |
| |
| static convcode_t convcode; |
| static editcode_t editcode; |
| static iocode_t iocode; |
| static unsigned long repetition; |
| static Boolean leftadjust; |
| static Boolean overflowev; |
| static Boolean dynamicwid; |
| static Boolean paddingdef; |
| static char paddingchar; |
| static Boolean fractiondef; |
| static unsigned long fractionwidth; |
| static Boolean exponentdef; |
| static unsigned long exponentwidth; |
| static unsigned long clausewidth; |
| static signed long textindex; |
| |
| static |
| __tmp_IO_enum_table_type bool_tab[] = |
| { { 0, "FALSE" }, |
| { 1, "TRUE" }, |
| { 0 , NULL } }; |
| |
| /* |
| * case insensitive compare: s1 is zero delimited, s2 has n chars |
| */ |
| static |
| int casncmp( const char* s1, const char* s2, int n ) |
| { |
| int res = 0; |
| while( n-- ) |
| { |
| if( (res = toupper(*s1++) - toupper(*s2++)) ) |
| return res; |
| } |
| return *s1; |
| } |
| |
| /* |
| * skip spaces with blank equal to tab |
| */ |
| static |
| int skip_space( int limit ) |
| { |
| int skipped = 0; |
| while( actual_index < limit && |
| (iostrptr[actual_index] == ' ' || iostrptr[actual_index] == '\t' ) ) |
| { |
| actual_index++; |
| skipped++; |
| } |
| return skipped; |
| } |
| |
| /* |
| * skip leading pad characters |
| */ |
| static |
| int skip_pad( int limit ) |
| { |
| int skipped = 0; |
| while( actual_index < limit && iostrptr[actual_index] == paddingchar ) |
| { |
| actual_index++; |
| skipped++; |
| } |
| #if _TEXTIO_DEBUG_ |
| printf( "skipping '%c' until %d: %d\n", paddingchar, limit, skipped ); |
| #endif |
| return skipped; |
| } |
| |
| /* |
| * backup trailing pad characters |
| */ |
| static |
| int piks_pad( int start, int limit ) |
| { |
| int skipped = 0; |
| while( start >/***=*/ limit && iostrptr[--start] == paddingchar ) |
| { |
| skipped++; |
| } |
| #if _TEXTIO_DEBUG_ |
| printf( "piksing '%c' from %d until %d: %d\n", |
| paddingchar, start, limit, skipped ); |
| #endif |
| return skipped; |
| } |
| |
| /* |
| * parse an integer |
| */ |
| static |
| int parse_int( int limit, int SET, int base, |
| unsigned long* valptr, int* signptr ) |
| { |
| int parsed = actual_index; |
| Boolean digits = False; |
| unsigned long value = 0; |
| char curr; |
| int dig; |
| |
| if( actual_index >= limit ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_INT ); |
| *signptr = +1; |
| if( iostrptr[actual_index] == '+' ) |
| actual_index++; |
| else |
| if( iostrptr[actual_index] == '-' ) |
| { *signptr = -1; |
| actual_index++; |
| } |
| |
| for( ; actual_index < limit; actual_index++ ) |
| { |
| curr = iostrptr[actual_index]; |
| if( curr == '_' ) continue; |
| if( isXXX(curr,SET) ) |
| { |
| digits = True; |
| dig = curr <= '9' ? curr - '0' : toupper(curr) - 'A' + 10; |
| if( value > (ULONG_MAX - dig)/base ) |
| IOEXCEPTION( TEXTFAIL, INT_VAL_OVERFLOW ); |
| value = value*base + dig; |
| continue; |
| } |
| break; |
| } |
| if( !digits ) |
| IOEXCEPTION( TEXTFAIL, NO_DIGITS_FOR_INT ); |
| |
| *valptr = value; |
| #if _TEXTIO_DEBUG_ |
| printf( "parsing for int until %d, base %d: %u\n", limit, base, value ); |
| #endif |
| return actual_index - parsed; |
| } |
| |
| static |
| double |
| make_float( int dexp, int sign ) |
| { |
| double value = atof( floatdig ); |
| #if _TEXTIO_DEBUG_ |
| printf( " value = %25.20e, dexp = %d\n", value, dexp ); |
| #endif |
| while( dexp >= 100 ) |
| value *= ep_100, dexp -= 100; |
| if( dexp >= 10 ) |
| value *= ep_10[dexp/10], dexp %= 10; |
| if( dexp > 0 ) |
| value *= ep_1[dexp]; |
| |
| while( dexp <= -100 ) |
| value /= ep_100, dexp += 100; |
| if( dexp <= -10 ) |
| value /= ep_10[-dexp/10], dexp %= 10; |
| if( dexp < 0 ) |
| value /= ep_1[-dexp]; |
| |
| return sign ? -value : value; |
| } |
| |
| /* %C -> fixed point [+|-]<digit>+[.<digit>*] */ |
| static |
| int parse_fixedpoint( int limit, double* valptr ) |
| { |
| int parsed = actual_index; |
| Boolean digits = False; |
| int sdig = 0; |
| double value; |
| char curr; |
| int sign = False; |
| int expo = 0; |
| |
| if( actual_index >= limit ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_FLOAT ); |
| if( iostrptr[actual_index] == '+' ) |
| actual_index++; |
| else |
| if( iostrptr[actual_index] == '-' ) |
| { |
| sign = True; |
| actual_index++; |
| } |
| |
| floatdig[0] = '.'; |
| for( ; actual_index < limit; actual_index++ ) |
| { |
| curr = iostrptr[actual_index]; |
| if( ! isDEC(curr) ) |
| break; |
| digits = True; |
| if( sdig < MAXPREC - 1 ) |
| { |
| if( sdig || curr != '0' ) |
| { |
| floatdig[++sdig] = curr; |
| expo++; |
| } |
| } |
| else |
| if( sdig ) |
| expo++; |
| } |
| if( digits && curr == '.' ) |
| { |
| actual_index++; |
| for( ; actual_index < limit; actual_index++ ) |
| { |
| curr = iostrptr[actual_index]; |
| if( !isDEC(curr) ) |
| break; |
| if( sdig < MAXPREC - 1 ) |
| { |
| if( sdig || curr != '0' ) |
| floatdig[++sdig] = curr; |
| else |
| expo--; |
| } |
| } |
| } |
| floatdig[++sdig] = '\0'; |
| |
| if( !digits ) |
| IOEXCEPTION( TEXTFAIL, NO_DIGITS_FOR_FLOAT ); |
| |
| *valptr = make_float( expo, sign); |
| return actual_index - parsed; |
| } |
| |
| |
| typedef enum { |
| s_sign, s_dig, s_period, s_fraca, s_fracb, s_expo, s_exposign, |
| s_expoa, s_expob } |
| scient_t; |
| |
| /* %C -> scientific [+|-]<digit>[.<digit>*]E[=|-]<digit>+ */ |
| static |
| int parse_scientific( int limit, double* valptr, double dmin, double dmax ) |
| { |
| int parsed = actual_index; |
| int sdig = 0; |
| char curr; |
| double value; |
| int sign = False; |
| int expo = 0; |
| int expo_sign = +1; |
| |
| scient_t state = s_sign; |
| |
| if( actual_index >= limit ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_FLOAT ); |
| |
| floatdig[0] = '.'; |
| for( ; actual_index < limit; actual_index++ ) |
| { |
| curr = iostrptr[actual_index]; |
| switch( state ) |
| { |
| case s_sign: |
| if( iostrptr[actual_index] == '+' ) |
| { |
| state = s_dig; |
| break; |
| } |
| if( iostrptr[actual_index] == '-' ) |
| { |
| sign = True; |
| state = s_dig; |
| break; |
| } |
| /* fall through - no break */ |
| case s_dig: |
| if( isDEC(curr) && curr > '0' ) |
| { |
| floatdig[++sdig] = curr; |
| state = s_period; |
| break; |
| } |
| IOEXCEPTION( TEXTFAIL, NO_DIGITS_FOR_FLOAT ); |
| case s_period: |
| if( curr == '.' ) |
| { |
| state = s_fraca; |
| break; |
| } |
| if( curr == 'E' ) |
| { |
| state = s_exposign; |
| break; |
| } |
| IOEXCEPTION( TEXTFAIL, NO_EXPONENT ); |
| case s_fraca: |
| if( isDEC(curr) ) |
| { |
| floatdig[++sdig] = curr; |
| state = s_fracb; |
| break; |
| } |
| IOEXCEPTION( TEXTFAIL, NO_DIGITS_FOR_FLOAT ); |
| case s_fracb: |
| if( isDEC(curr) ) |
| { |
| if( sdig < MAXPREC - 1 ) |
| floatdig[++sdig] = curr; |
| break; |
| } |
| if( curr == 'E' ) |
| { |
| state = s_exposign; |
| break; |
| } |
| IOEXCEPTION( TEXTFAIL, NO_EXPONENT ); |
| case s_exposign: |
| if( iostrptr[actual_index] == '+' ) |
| { |
| state = s_expoa; |
| break; |
| } |
| if( iostrptr[actual_index] == '-' ) |
| { |
| expo_sign = -1; |
| state = s_expoa; |
| break; |
| } |
| case s_expoa: |
| if( isDEC(curr) ) |
| { |
| expo = curr - '0'; |
| state = s_expob; |
| break; |
| } |
| IOEXCEPTION( TEXTFAIL, NO_EXPONENT ); |
| case s_expob: |
| expo = expo*10 + (curr - '0'); |
| if( expo > 1000 ) |
| IOEXCEPTION( TEXTFAIL, REAL_OVERFLOW ); |
| } |
| } |
| if( state != s_expob ) |
| IOEXCEPTION( TEXTFAIL, NO_EXPONENT ); |
| |
| expo *= expo_sign; |
| expo++; |
| |
| floatdig[++sdig] = '\0'; |
| |
| *valptr = make_float( expo, sign ); |
| return actual_index - parsed; |
| } |
| |
| |
| static |
| int parse_set( int limit, __tmp_IO_enum_table_type* tabptr, |
| unsigned long* valptr ) |
| { |
| int parsed = actual_index; |
| char curr; |
| __tmp_IO_enum_table_type* etptr; |
| |
| if( actual_index >= limit ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_SET ); |
| |
| curr = iostrptr[actual_index]; |
| if( isXXX(curr,LET+USC) ) |
| actual_index++; |
| else |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_SET ); |
| |
| for( ; actual_index < limit; actual_index++ ) |
| { |
| if( ! isXXX(iostrptr[actual_index],LET+DEC+USC) ) |
| break; |
| } |
| |
| if( tabptr ) |
| while( tabptr->name ) |
| { |
| if( !casncmp( tabptr->name, &iostrptr[parsed], actual_index-parsed ) ) |
| { |
| *valptr = tabptr->value; |
| #if _TEXTIO_DEBUG_ |
| printf( "parsing set value until %d: %u\n", limit, tabptr->value ); |
| #endif |
| return actual_index - parsed; |
| } |
| tabptr++; |
| } |
| IOEXCEPTION( TEXTFAIL, SET_CONVERSION_ERROR ); |
| } |
| |
| static |
| int parse_bit( int limit, char* bitptr ) |
| { |
| int parsed = actual_index; |
| int i = 0; |
| char curr; |
| |
| if( actual_index >= limit ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_BOOLS ); |
| |
| for( ; actual_index < limit; actual_index++ ) |
| { |
| curr = iostrptr[actual_index] - '0'; |
| if( curr == 0 || curr == 1 ) |
| /* __setbitinset( i++, bitptr, limit, curr ); */ |
| __setbitpowerset (bitptr, limit, 0, i++, curr, __FILE__, __LINE__); |
| else |
| break; |
| } |
| return actual_index - parsed; |
| } |
| |
| static |
| char* myultoa( unsigned long ul, char* buf, int base ) |
| { |
| char* res = buf; |
| unsigned long h = ul/base; |
| unsigned long q = 1; |
| |
| while( h >= q ) q *= base; |
| while( q > 0 ) |
| { |
| *buf++ = "0123456789ABCDEF"[ul/q]; |
| ul %= q; |
| q /= base; |
| } |
| *buf++ = '\0'; |
| return res; |
| } |
| |
| /* |
| * convert a bit string from src, bit offset up to len |
| */ |
| static |
| char* bitput( char* dst, char* src, int offset, int len ) |
| { |
| char* res = dst; |
| int i; |
| for( i = offset; i < len; i++ ) |
| { |
| *dst++ = __inpowerset( i, src, len, 0 ) ? '1' : '0'; |
| } |
| return res; |
| } |
| |
| /* |
| * dround: round decimal register *digptr starting at digit mdigs, |
| * on carry advance begin of digit sequence and bump exponent |
| */ |
| static |
| char* |
| dround( char* digptr, int mdigs, int* deptr ) |
| { |
| int carry; |
| #if _TEXTIO_DEBUG_ |
| printf( "Rounding from %d\n", mdigs ); |
| #endif |
| if( digptr[mdigs] >= 5 ) |
| { |
| carry = 1; |
| while( carry ) |
| { |
| digptr[--mdigs]++; |
| if( digptr[mdigs] >= 10 ) |
| digptr[mdigs] = 0; |
| else |
| carry = 0; |
| } |
| } |
| if( mdigs < 0 ) |
| { |
| digptr[--mdigs] = 1; |
| (*deptr)++; |
| return digptr - 1; |
| } |
| else |
| return digptr; |
| } |
| |
| /* |
| * mydtoa: convert val with a precision of mantdigs to a decimal fraction |
| * first digit is at **fstdiptr, decimal exponent is at *deptr |
| */ |
| static |
| char* |
| mydtoa( double val, int mantdigs, int* deptr, int* sgnptr ) |
| { |
| double m; |
| int be; |
| int de = -1; |
| int fstdig = 0; |
| int idig; |
| char* digptr = floatdig+2; |
| |
| floatdig[0] = floatdig[1] = 0; |
| |
| if( val < 0 ) |
| *sgnptr = -1, val = fabs( val ); |
| else |
| *sgnptr = +1; |
| |
| /* split the value */ |
| m = frexp( val, &be ) * 10.0; |
| |
| /* 5.0 <= m < 10.0 */ |
| while( be > 0 ) |
| { |
| de++; be--; m /= 5.0; |
| if( m < 1.0 ) |
| m *= 10.0, de--; |
| } |
| while( be < 0 ) |
| { |
| de--; be++; m *= 5.0; |
| if( m >= 10.0 ) |
| m /= 10.0, de++; |
| } |
| |
| for( idig = 0; idig < mantdigs; idig++ ) |
| { |
| digptr[idig] = (int)m; |
| m = (m - digptr[idig])*10.0; |
| } |
| digptr[idig] = (int)m; |
| |
| *deptr = de; |
| return dround( digptr, mantdigs, deptr ); |
| } |
| |
| #define PUT(c) \ |
| { if( ifst <= ++iprt && iprt <= ilst ) *dst++ = c; } |
| |
| static |
| char* |
| fixput( char* dst, char* src, |
| int ifst, int ilst, |
| int sign, int fst, int lst, |
| int nid, int nfd ) |
| { |
| char* dstsav = dst; |
| int idig; |
| int iprt = 0; |
| |
| if( sign < 0 ) |
| PUT( '-' ); |
| for( idig = nid; idig >= -nfd; idig-- ) |
| { |
| if (idig == -1) |
| PUT( '.' ); |
| PUT( idig > fst || lst >= idig ? '0': '0' + *src++ ); |
| } |
| return dstsav; |
| } |
| |
| static |
| char* |
| sciput( char* dst, char* src, char* expbeg, |
| int ifst, int ilst, |
| int sign, int de, int expwid ) |
| { |
| char* dstsav = dst; |
| int iprt = 0; |
| int nfd = fractionwidth; |
| int explen = strlen( expbeg ); |
| |
| if( sign < 0 ) |
| PUT( '-' ); |
| PUT( '0' + *src++ ); |
| PUT( '.' ); |
| |
| while( nfd-- ) |
| PUT( '0' + *src++ ); |
| PUT( 'E' ); |
| PUT( de >= 0 ? '+' : '-' ); |
| while( expwid > explen ) |
| { |
| PUT( '0' ); |
| expwid--; |
| } |
| while( explen-- ) |
| PUT( *expbeg++ ); |
| return dstsav; |
| } |
| |
| /* |
| * handle dynamic field width |
| */ |
| static |
| get_field_width( void ) |
| { |
| unsigned long width; |
| unsigned long ulongval; |
| long longval; |
| __tmp_IO_list io; |
| |
| |
| if( ++iolist_index > iolistlen ) |
| IOEXCEPTION( TEXTFAIL, IOLIST_EXHAUSTED ); |
| |
| io = *iolistptr++; |
| |
| /* must be integer, >= 0 */ |
| switch( io.__descr ) |
| { |
| case __IO_ByteVal: |
| longval = io.__t.__valbyte; |
| goto signed_fieldwidth; |
| case __IO_UByteVal: |
| width = io.__t.__valubyte; |
| goto unsigned_fieldwidth; |
| case __IO_IntVal: |
| longval = io.__t.__valint; |
| goto signed_fieldwidth; |
| case __IO_UIntVal: |
| width = io.__t.__valuint; |
| goto unsigned_fieldwidth; |
| case __IO_LongVal: |
| longval = io.__t.__vallong; |
| goto signed_fieldwidth; |
| case __IO_ULongVal: |
| width = io.__t.__valulong; |
| goto unsigned_fieldwidth; |
| case __IO_ByteLoc: |
| longval = *(signed char*)io.__t.__locint; |
| goto signed_fieldwidth; |
| case __IO_UByteLoc: |
| width = *(unsigned char*)io.__t.__locint; |
| goto unsigned_fieldwidth; |
| case __IO_IntLoc: |
| longval = *(signed short*)io.__t.__locint; |
| goto signed_fieldwidth; |
| case __IO_UIntLoc: |
| width = *(unsigned short*)io.__t.__locint; |
| goto unsigned_fieldwidth; |
| case __IO_LongLoc: |
| longval = *(signed long*) io.__t.__locint; |
| goto signed_fieldwidth; |
| case __IO_ULongLoc: |
| width = *(unsigned long*)io.__t.__locint; |
| goto unsigned_fieldwidth; |
| default: |
| IOEXCEPTION( TEXTFAIL, NON_INT_FIELD_WIDTH ); |
| } |
| |
| signed_fieldwidth: ; |
| if( longval < 0 ) |
| IOEXCEPTION( TEXTFAIL, NEGATIVE_FIELD_WIDTH ); |
| width = longval; |
| |
| unsigned_fieldwidth: ; |
| return width; |
| } |
| |
| |
| static |
| void inpconv( void ) |
| { |
| __tmp_IO_list io; |
| int width; |
| int limit; |
| int skiplim; |
| int skipped; |
| int bypass; |
| int parsed; |
| Boolean fixedchars; |
| int fixedlen; |
| unsigned char curr; |
| double dval; |
| float fval; |
| |
| __tmp_IO_long lval; |
| int sign; |
| unsigned long umin; |
| unsigned long umax; |
| signed long smin; |
| signed long smax; |
| int ilen; |
| short unsigned slen; |
| __tmp_IO_enum_table_type* settabptr; |
| |
| while( repetition-- ) |
| { |
| if( ++iolist_index > iolistlen ) |
| IOEXCEPTION( TEXTFAIL, IOLIST_EXHAUSTED ); |
| |
| io = *iolistptr++; |
| |
| if( dynamicwid ) |
| width = get_field_width(); |
| else |
| width = clausewidth; |
| |
| bypass = skipped = 0; |
| if( width ) |
| { |
| if( actual_index + width > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, NOT_ENOUGH_CHARS ); |
| |
| switch(io.__descr) |
| { |
| case __IO_CharLoc: |
| case __IO_CharRangeLoc: |
| fixedchars = True; |
| fixedlen = 1; |
| break; |
| case __IO_CharStrLoc: |
| fixedchars = True; |
| fixedlen = io.__t.__loccharstring.string_length; |
| break; |
| default: |
| fixedchars = False; |
| break; |
| } |
| |
| if( leftadjust ) |
| { |
| skiplim = fixedchars ? actual_index + fixedlen |
| : actual_index; |
| bypass = skipped = piks_pad( actual_index + width, skiplim ); |
| } |
| else |
| { |
| skiplim = fixedchars ? actual_index + width - fixedlen |
| : actual_index + width; |
| skipped = skip_pad( skiplim ); |
| } |
| width -= skipped; |
| limit = actual_index + width; |
| } |
| else |
| { /* free format */ |
| if( paddingdef || !( io.__descr == __IO_CharLoc || |
| io.__descr == __IO_CharRangeLoc || |
| io.__descr == __IO_CharStrLoc || |
| io.__descr == __IO_CharVaryingLoc ) ) |
| if( paddingchar == ' ' || paddingchar == '\t' ) |
| skip_space( iostrlen ); |
| else |
| skip_pad( iostrlen ); |
| limit = iostrlen; |
| } |
| |
| switch( io.__descr ) |
| { |
| case __IO_ByteLoc: |
| ilen = 1; |
| smin = CH_BYTE_MIN; |
| smax = CH_BYTE_MAX; |
| goto parse_signed_int; |
| case __IO_UByteLoc: |
| ilen = 1; |
| umin = 0; |
| umax = CH_UBYTE_MAX; |
| goto parse_unsigned_int; |
| case __IO_IntLoc: |
| ilen = 2; |
| smin = CH_INT_MIN; |
| smax = CH_INT_MAX; |
| goto parse_signed_int; |
| case __IO_UIntLoc: |
| ilen = 2; |
| umin = 0; |
| umax = CH_UINT_MAX; |
| goto parse_unsigned_int; |
| case __IO_LongLoc: |
| ilen = 4; |
| smin = CH_LONG_MIN; |
| smax = CH_LONG_MAX; |
| goto parse_signed_int; |
| case __IO_ULongLoc: |
| ilen = 4; |
| umin = 0; |
| umax = CH_ULONG_MAX; |
| goto parse_unsigned_int; |
| |
| case __IO_ByteRangeLoc: |
| ilen = 1; |
| smin = io.__t.__locintrange.lower.slong; |
| smax = io.__t.__locintrange.upper.slong; |
| goto parse_signed_int; |
| case __IO_UByteRangeLoc: |
| ilen = 1; |
| umin = io.__t.__locintrange.lower.ulong; |
| umax = io.__t.__locintrange.upper.ulong; |
| goto parse_unsigned_int; |
| case __IO_IntRangeLoc: |
| ilen = 2; |
| smin = io.__t.__locintrange.lower.slong; |
| smax = io.__t.__locintrange.upper.slong; |
| goto parse_signed_int; |
| case __IO_UIntRangeLoc: |
| ilen = 2; |
| umin = io.__t.__locintrange.lower.ulong; |
| umax = io.__t.__locintrange.upper.ulong; |
| goto parse_unsigned_int; |
| case __IO_LongRangeLoc: |
| ilen = 4; |
| smin = io.__t.__locintrange.lower.slong; |
| smax = io.__t.__locintrange.upper.slong; |
| goto parse_signed_int; |
| case __IO_ULongRangeLoc: |
| ilen = 4; |
| umin = io.__t.__locintrange.lower.ulong; |
| umax = io.__t.__locintrange.upper.ulong; |
| goto parse_unsigned_int; |
| |
| case __IO_BoolLoc: |
| ilen = 1; |
| umin = 0; |
| umax = 1; |
| settabptr = bool_tab; |
| goto parse_set; |
| case __IO_BoolRangeLoc: |
| ilen = 1; |
| umin = io.__t.__locboolrange.lower; |
| umax = io.__t.__locboolrange.upper; |
| settabptr = bool_tab; |
| goto parse_set; |
| |
| case __IO_SetLoc: |
| ilen = io.__t.__locsetrange.length; |
| settabptr = io.__t.__locsetrange.name_table; |
| umin = 0; |
| umax = CH_ULONG_MAX; |
| goto parse_set; |
| case __IO_SetRangeLoc: |
| ilen = io.__t.__locsetrange.length; |
| settabptr = io.__t.__locsetrange.name_table; |
| umin = io.__t.__locsetrange.lower; |
| umax = io.__t.__locsetrange.upper; |
| goto parse_set; |
| |
| case __IO_CharLoc: |
| umin = 0; |
| umax = 0xff; |
| goto parse_char; |
| case __IO_CharRangeLoc: |
| umin = io.__t.__loccharrange.lower; |
| umax = io.__t.__loccharrange.upper; |
| goto parse_char; |
| |
| case __IO_CharVaryingLoc: |
| if( convcode != DefaultConv ) |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| slen = io.__t.__loccharstring.string_length; |
| if( (parsed = limit - actual_index) < slen ) |
| slen = parsed; |
| else |
| parsed = slen; |
| memcpy( io.__t.__loccharstring.string + 2, |
| &iostrptr[actual_index], parsed ); |
| MOV2(io.__t.__loccharstring.string,&slen); |
| actual_index += parsed; |
| goto check_field_complete; |
| |
| |
| case __IO_CharStrLoc: |
| if( convcode != DefaultConv ) |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| if( actual_index + io.__t.__loccharstring.string_length > limit ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_CHARS ); |
| memcpy( io.__t.__loccharstring.string, |
| &iostrptr[actual_index], |
| parsed = io.__t.__loccharstring.string_length ); |
| actual_index += parsed; |
| goto check_field_complete; |
| |
| case __IO_BitStrLoc: |
| if( convcode != DefaultConv ) |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| parsed = parse_bit( limit, io.__t.__loccharstring.string ); |
| if( parsed < io.__t.__loccharstring.string_length ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_BOOLS ); |
| goto check_field_complete; |
| |
| case __IO_LongRealLoc: |
| case __IO_RealLoc: |
| switch( convcode ) |
| { |
| case ScientConv: |
| parse_scientific( limit, &dval, DBL_MIN, DBL_MAX ); |
| break; |
| case DefaultConv: |
| parse_fixedpoint( limit, &dval ); |
| break; |
| default: |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| } |
| if( io.__descr == __IO_LongRealLoc ) |
| memcpy( io.__t.__loclongreal, &dval, sizeof(double) ); |
| else |
| { |
| fval = (float)dval; |
| MOV4(io.__t.__locreal,&fval); |
| } |
| goto check_field_complete; |
| default: |
| IOEXCEPTION( TEXTFAIL, INVALID_IO_LIST ); |
| } |
| |
| |
| parse_signed_int: ; |
| if( convcode == ScientConv ) |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| parsed = parse_int( limit, dset[convcode], base[convcode], |
| &lval.ulong, &sign ); |
| if( sign < 0 ) |
| { |
| if( lval.ulong > (unsigned long)CH_LONG_MIN ) |
| IOEXCEPTION( TEXTFAIL, INTEGER_RANGE_ERROR ); |
| lval.slong = -lval.ulong; |
| } |
| else |
| { |
| /* not needed: lval.slong = lval.ulong; */ |
| /* Hack: sign extension for bin/oct/dec if no sign present */ |
| if( convcode != DefaultConv && lval.ulong & (1 << (ilen*8-1)) ) |
| { |
| if( ilen < 4 ) |
| lval.ulong |= 0xFFFFFFFF << ilen*8; |
| } |
| else |
| if( lval.ulong > (unsigned long)CH_LONG_MAX ) |
| IOEXCEPTION( TEXTFAIL, INTEGER_RANGE_ERROR ); |
| } |
| if( lval.slong < smin || smax < lval.slong ) |
| IOEXCEPTION( TEXTFAIL, INTEGER_RANGE_ERROR ); |
| goto store_int; |
| |
| parse_unsigned_int: ; |
| if( convcode == ScientConv ) |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| parsed = parse_int( limit, dset[convcode], base[convcode], |
| &lval.ulong, &sign ); |
| if( sign < 0 || lval.ulong < umin || umax < lval.ulong ) |
| IOEXCEPTION( TEXTFAIL, INTEGER_RANGE_ERROR ); |
| goto store_int; |
| |
| parse_set: ; |
| if( convcode != DefaultConv ) |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| parsed = parse_set( limit, settabptr, &lval.ulong ); |
| if( lval.ulong < umin || umax < lval.ulong ) |
| IOEXCEPTION( TEXTFAIL, SET_RANGE_ERROR ); |
| goto store_int; |
| |
| store_int: ; |
| switch( ilen ) |
| { |
| case 1: |
| *(unsigned char*)io.__t.__locint = lval.ulong; |
| break; |
| case 2: |
| slen = lval.ulong; |
| MOV2(io.__t.__locint,&slen); |
| break; |
| case 4: |
| MOV4(io.__t.__locint,&lval.ulong); |
| break; |
| default: |
| IOEXCEPTION( TEXTFAIL, INTERNAL_ERROR ); |
| } |
| goto check_field_complete; |
| |
| parse_char: ; |
| if( convcode != DefaultConv ) |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| if( actual_index >= limit ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_CHARS ); |
| curr = iostrptr[actual_index++]; |
| parsed = 1; |
| if( curr < umin || umax < curr ) |
| IOEXCEPTION( TEXTFAIL, CHAR_RANGE_ERROR ); |
| *io.__t.__locchar = curr; |
| goto check_field_complete; |
| |
| check_field_complete: ; |
| actual_index += bypass; |
| if( width > parsed ) |
| IOEXCEPTION( TEXTFAIL, INVALID_CHAR ); |
| } |
| } |
| |
| static |
| void inpedit( void ) |
| { |
| int nchars; |
| |
| if( dynamicwid ) |
| clausewidth = get_field_width(); |
| |
| switch( editcode ) |
| { |
| case SpaceSkip: |
| nchars = repetition*clausewidth; |
| if( actual_index + nchars > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_EDIT ); |
| for( ; nchars ; nchars-- ) |
| if( iostrptr[actual_index++] != ' ' ) |
| IOEXCEPTION( TEXTFAIL, NO_SPACE_TO_SKIP ); |
| break; |
| |
| case SkipLeft: |
| nchars = repetition*clausewidth; |
| if( (actual_index -= nchars) < 0 ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_EDIT ); |
| break; |
| |
| case SkipRight: |
| nchars = repetition*clausewidth; |
| if( (actual_index += nchars) > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_EDIT ); |
| break; |
| |
| case Tabulation: |
| if( (actual_index = clausewidth) > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| break; |
| } |
| } |
| |
| static |
| void outconv( void ) |
| { |
| unsigned long width; |
| char itembuf[33]; |
| unsigned long ulongval; |
| long longval; |
| __tmp_IO_list io; |
| __tmp_IO_enum_table_type* etptr; |
| char* itembeg; |
| unsigned long itemlen; |
| double doubleval; |
| int de; |
| int sign; |
| int mantdigs; |
| int nid; |
| int nfd; |
| char* expbeg; |
| int explen; |
| unsigned int expwid; |
| |
| while( repetition-- ) |
| { |
| if( ++iolist_index > iolistlen ) |
| IOEXCEPTION( TEXTFAIL, IOLIST_EXHAUSTED ); |
| |
| io = *iolistptr++; |
| width = dynamicwid ? get_field_width() : clausewidth; |
| |
| switch( convcode ) |
| { |
| case DefaultConv: |
| switch( io.__descr ) |
| { |
| case __IO_ByteVal: |
| longval = io.__t.__valbyte; |
| goto signed_conversion; |
| case __IO_UByteVal: |
| ulongval = io.__t.__valubyte; |
| goto unsigned_conversion; |
| case __IO_IntVal: |
| longval = io.__t.__valint; |
| goto signed_conversion; |
| case __IO_UIntVal: |
| ulongval = io.__t.__valuint; |
| goto unsigned_conversion; |
| case __IO_LongVal: |
| longval = io.__t.__vallong; |
| goto signed_conversion; |
| case __IO_ULongVal: |
| ulongval = io.__t.__valulong; |
| goto unsigned_conversion; |
| |
| case __IO_BoolVal: |
| switch( io.__t.__valbool ) |
| { |
| case 0: |
| itembeg = "FALSE"; |
| itemlen = 5; |
| goto move_item; |
| case 1: |
| itembeg = "TRUE"; |
| itemlen = 4; |
| goto move_item; |
| default: |
| IOEXCEPTION( TEXTFAIL, BOOL_CONVERSION_ERROR ); |
| } |
| |
| case __IO_CharVal: |
| itembeg = &io.__t.__valchar; |
| itemlen = 1; |
| goto move_item; |
| |
| case __IO_SetVal: |
| /* locate name string using set mode name table */ |
| itembeg = 0; |
| |
| if( (etptr = io.__t.__valset.name_table) ) |
| while( etptr->name ) |
| { |
| if( etptr->value == io.__t.__valset.value ) |
| { |
| itembeg = etptr->name; |
| itemlen = strlen( itembeg ); |
| goto move_item; |
| } |
| etptr++; |
| } |
| IOEXCEPTION( TEXTFAIL, SET_CONVERSION_ERROR ); |
| |
| case __IO_CharVaryingLoc: |
| { |
| unsigned short l; |
| itembeg = (char*)io.__t.__loccharstring.string; |
| MOV2(&l,itembeg); |
| itembeg += 2; |
| itemlen = l; |
| goto move_item; |
| } |
| |
| case __IO_CharStrLoc: |
| itembeg = io.__t.__loccharstring.string; |
| itemlen = io.__t.__loccharstring.string_length; |
| goto move_item; |
| |
| case __IO_BitStrLoc: |
| itemlen = io.__t.__loccharstring.string_length; |
| itembeg = io.__t.__loccharstring.string; |
| |
| if( !width ) |
| width = itemlen; |
| |
| /* check remaining space */ |
| if( actual_index + width > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| |
| if( itemlen == width ) |
| bitput( iostrptr + actual_index, itembeg, 0, itemlen ); |
| else |
| if( itemlen < width ) |
| if( leftadjust ) |
| memset( bitput( iostrptr + actual_index, itembeg, 0, itemlen ) |
| + itemlen, |
| paddingchar, width - itemlen ); |
| else |
| bitput( memset( iostrptr + actual_index, |
| paddingchar, width - itemlen ) |
| + width - itemlen, |
| itembeg, itemlen - width, itemlen ); |
| else |
| if( overflowev ) |
| memset( iostrptr + actual_index, '*', width ); |
| else |
| if( leftadjust ) |
| bitput( iostrptr + actual_index, itembeg, 0, width ); |
| else |
| bitput( iostrptr + actual_index, itembeg, |
| itemlen - width, itemlen ); |
| goto adjust_index; |
| |
| case __IO_RealVal: |
| doubleval = io.__t.__valreal; |
| mantdigs = FMANTDIGS; |
| goto fixed_point_conversion; |
| case __IO_LongRealVal: |
| doubleval = io.__t.__vallongreal; |
| mantdigs = DBL_DIG; |
| goto fixed_point_conversion; |
| break; |
| |
| default: |
| IOEXCEPTION( TEXTFAIL, INVALID_IO_LIST ); |
| } |
| |
| case HexConv: |
| case OctalConv: |
| case BinaryConv: |
| switch( io.__descr ) |
| { |
| case __IO_ByteVal: |
| case __IO_UByteVal: |
| ulongval = io.__t.__valubyte; |
| break; |
| case __IO_IntVal: |
| case __IO_UIntVal: |
| ulongval = io.__t.__valuint; |
| break; |
| case __IO_LongVal: |
| case __IO_ULongVal: |
| ulongval = io.__t.__valulong; |
| break; |
| default: |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| } |
| itembeg = myultoa( ulongval, itembuf, base[convcode] ); |
| itemlen = strlen( itembeg ); |
| goto move_item; |
| |
| case ScientConv: |
| switch( io.__descr ) |
| { |
| case __IO_RealVal: |
| doubleval = io.__t.__valreal; |
| mantdigs = FMANTDIGS; |
| if( !fractiondef ) |
| fractionwidth = FMANTDIGS - 1; |
| goto scientific_conversion; |
| case __IO_LongRealVal: |
| doubleval = io.__t.__vallongreal; |
| mantdigs = DBL_DIG; |
| if( !fractiondef ) |
| fractionwidth = DBL_DIG - 1; |
| goto scientific_conversion; |
| break; |
| default: |
| IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT ); |
| } |
| } |
| |
| fixed_point_conversion: ; |
| itembeg = mydtoa( doubleval, mantdigs, &de, &sign ); |
| if( fractiondef && de >= -fractionwidth - 1 |
| && -fractionwidth > de - mantdigs ) |
| itembeg = dround( itembeg, de + fractionwidth + 1, &de ); |
| |
| nid = de >= 0 ? de : 0; |
| nfd = fractiondef ? fractionwidth |
| : ( de + 1 - mantdigs > 0 ? 0 : mantdigs - de - 1 ); |
| itemlen = ( sign < 0 ? 1 : 0 ) + 2 + nid + nfd; |
| #if _TEXTIO_DEBUG_ |
| printf( "fixed item length %d\n", itemlen ); |
| #endif |
| if( !width ) |
| width = itemlen; |
| #if _TEXTIO_DEBUG_ |
| printf( "fixed item width %d\n", width ); |
| #endif |
| /* check remaining space */ |
| if( actual_index + width > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| |
| if( itemlen == width ) |
| fixput( iostrptr + actual_index, itembeg, |
| 1, itemlen, sign, de, de - mantdigs, nid, nfd ); |
| else |
| if( itemlen < width ) |
| if( leftadjust ) |
| memset( fixput( iostrptr + actual_index, itembeg, |
| 1, itemlen, sign, de, de - mantdigs, nid, nfd ) |
| + itemlen, |
| paddingchar, width - itemlen ); |
| else |
| fixput( memset( iostrptr + actual_index, |
| paddingchar, width - itemlen ) |
| + width - itemlen, |
| itembeg, 1, itemlen, sign, de, de - mantdigs, nid, nfd ); |
| else |
| if( overflowev ) |
| memset( iostrptr + actual_index, '*', width ); |
| else |
| if( leftadjust ) |
| fixput( iostrptr + actual_index, itembeg, |
| 1, width, sign, de, de - mantdigs, nid, nfd ); |
| else |
| fixput( iostrptr + actual_index, itembeg, |
| itemlen - width + 1, itemlen, |
| sign, de, de - mantdigs, nid, nfd ); |
| goto adjust_index; |
| |
| scientific_conversion: ; |
| itembeg = mydtoa( doubleval, mantdigs, &de, &sign ); |
| |
| if( fractiondef && fractionwidth < mantdigs ) |
| itembeg = dround( itembeg, fractionwidth + 1, &de ); |
| |
| expbeg = myultoa( abs(de), itembuf, 10 ); |
| explen = strlen( expbeg ); |
| |
| expwid = explen > exponentwidth ? explen : exponentwidth; |
| itemlen = ( sign < 0 ? 1 : 0 ) + 2 + fractionwidth + 2 + expwid; |
| #if _TEXTIO_DEBUG_ |
| printf( "floating item length %d, fraction %d, exponent %d\n", |
| itemlen, fractionwidth, expwid ); |
| #endif |
| if( width == 0 ) |
| width = itemlen; |
| #if _TEXTIO_DEBUG_ |
| printf( "floating item width %d\n", width ); |
| #endif |
| /* check remaining space */ |
| if( actual_index + width > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| |
| if( itemlen == width ) |
| sciput( iostrptr + actual_index, itembeg, expbeg, |
| 1, itemlen, sign, de, expwid ); |
| else |
| if( itemlen < width ) |
| if( leftadjust ) |
| memset( sciput( iostrptr + actual_index, itembeg, expbeg, |
| 1, itemlen, sign, de, expwid ) |
| + itemlen, |
| paddingchar, width - itemlen ); |
| else |
| sciput( memset( iostrptr + actual_index, |
| paddingchar, width - itemlen ) |
| + width - itemlen, |
| itembeg, expbeg, 1, itemlen, sign, de, expwid ); |
| else |
| if( overflowev ) |
| memset( iostrptr + actual_index, '*', width ); |
| else |
| if( leftadjust ) |
| sciput( iostrptr + actual_index, itembeg, expbeg, |
| 1, width, sign, de, expwid ); |
| else |
| sciput( iostrptr + actual_index, itembeg, expbeg, |
| itemlen - width + 1, itemlen, |
| sign, de, expwid ); |
| goto adjust_index; |
| |
| signed_conversion: ; |
| if( longval >= 0 ) |
| itembeg = myultoa( longval, itembuf, 10 ); |
| else |
| { |
| itembuf[0] = '-'; |
| myultoa( -longval, itembuf+1, 10 ); |
| itembeg = itembuf; |
| } |
| itemlen = strlen( itembeg ); |
| goto move_item; |
| |
| unsigned_conversion: ; |
| itembeg = myultoa( ulongval, itembuf, 10 ); |
| itemlen = strlen( itembeg ); |
| goto move_item; |
| |
| move_item: ; |
| if( !width ) |
| width = itemlen; |
| |
| /* check remaining space */ |
| if( actual_index + width > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| |
| /* move item, filling or truncating or overflow-evidencing */ |
| if( itemlen == width ) |
| memcpy( iostrptr + actual_index, itembeg, itemlen ); |
| else |
| if( itemlen < width ) |
| if( leftadjust ) |
| memset( memcpy( iostrptr + actual_index, itembeg, itemlen ) |
| + itemlen, |
| paddingchar, width - itemlen ); |
| else |
| memcpy( memset( iostrptr + actual_index, |
| paddingchar, width - itemlen ) |
| + width - itemlen, |
| itembeg, itemlen ); |
| else |
| if( overflowev ) |
| memset( iostrptr + actual_index, '*', width ); |
| else |
| if( leftadjust ) |
| memcpy( iostrptr + actual_index, itembeg, width ); |
| else |
| memcpy( iostrptr + actual_index, |
| itembeg + itemlen - width, width ); |
| |
| /* |
| * adjust. |
| */ |
| adjust_index: ; |
| actual_index += width; |
| if( actual_index > maximum_index ) |
| maximum_index = actual_index; |
| } |
| } |
| |
| static |
| void outedit( void ) |
| { |
| int nchars; |
| |
| if( dynamicwid ) |
| clausewidth = get_field_width(); |
| switch( editcode ) |
| { |
| case SpaceSkip: |
| nchars = repetition*clausewidth; |
| if( actual_index + nchars > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| memset( iostrptr + actual_index, ' ', nchars ); |
| actual_index += nchars; |
| if( actual_index > maximum_index ) |
| maximum_index = actual_index; |
| break; |
| |
| case SkipLeft: |
| nchars = repetition*clausewidth; |
| if( actual_index - nchars < 0 ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| actual_index -= nchars; |
| break; |
| |
| case SkipRight: |
| nchars = repetition*clausewidth; |
| if( actual_index + nchars > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| actual_index += nchars; |
| if( actual_index > maximum_index ) |
| { |
| memset( iostrptr + maximum_index, ' ', actual_index - maximum_index ); |
| maximum_index = actual_index; |
| } |
| break; |
| |
| case Tabulation: |
| if( clausewidth >= iostrlen ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| actual_index = clausewidth; |
| if( actual_index > maximum_index ) |
| { |
| memset( iostrptr + maximum_index, ' ', actual_index - maximum_index ); |
| maximum_index = actual_index; |
| } |
| break; |
| } |
| } |
| |
| |
| static |
| void inpioctrl( void ) |
| { |
| unsigned short hlen; |
| if( !textptr ) |
| IOEXCEPTION( TEXTFAIL, IO_CONTROL_NOT_VALID ); |
| if( iocode != EndPage ) |
| { |
| jmp_buf ioerror; |
| unsigned long info; |
| |
| if (textptr->access_sub->association) |
| { |
| if( (info = setjmp( ioerror )) ) |
| IOEXCEPTION( info>>16, info & 0xffff ); |
| while( repetition-- ) |
| { |
| __readrecord( textptr->access_sub, textindex, |
| (char*)textptr->text_record, |
| __FILE__, __LINE__ ); |
| actual_index = 0; |
| MOV2(&hlen,&textptr->text_record->len); |
| iostrlen = hlen; |
| } |
| } |
| else |
| IOEXCEPTION (NOTCONNECTED, IS_NOT_CONNECTED); |
| } |
| } |
| |
| /* specify pre/post in the order "/+-?!" */ |
| static |
| char* pre_char = "\0\f\0\r\0"; /* Z.200: "\n\f\0\n\0" */ |
| static |
| char* post_char = "\n\n\r\0\0"; /* Z.200: "\r\r\r\0\0" */ |
| |
| static |
| void outioctrl( void ) |
| { |
| Association_Mode* assoc; |
| unsigned short hlen; |
| if( !textptr ) |
| IOEXCEPTION( TEXTFAIL, IO_CONTROL_NOT_VALID ); |
| if( (assoc = textptr->access_sub->association) ) |
| { |
| jmp_buf ioerror; |
| unsigned long info; |
| if( (info = setjmp( ioerror )) ) |
| IOEXCEPTION( info>>16, info & 0xffff ); |
| |
| while( repetition-- ) |
| { |
| if( iocode != EndPage ) |
| { |
| if( TEST_FLAG( assoc, IO_FIRSTLINE ) ) |
| { |
| CLR_FLAG( assoc, IO_FIRSTLINE ); |
| assoc->ctl_pre = '\0'; |
| } |
| else |
| { |
| if( TEST_FLAG( assoc, IO_FORCE_PAGE ) ) |
| { |
| CLR_FLAG( assoc, IO_FORCE_PAGE ); |
| assoc->ctl_pre = '\f'; |
| } |
| else |
| assoc->ctl_pre = pre_char[iocode]; |
| } |
| assoc->ctl_post = post_char[iocode]; |
| hlen = actual_index; |
| MOV2(&textptr->text_record->len,&hlen); |
| __writerecord( textptr->access_sub, textindex, |
| (char*)textptr->text_record, |
| textptr->text_record->len, |
| __FILE__, __LINE__ ); |
| hlen = actual_index = 0; |
| MOV2(&textptr->text_record->len,&hlen); |
| } |
| else if( !TEST_FLAG( textptr, IO_FIRSTLINE ) ) |
| SET_FLAG( textptr, IO_FORCE_PAGE ); |
| assoc->ctl_pre = assoc->ctl_post = '\0'; |
| } |
| } |
| else |
| IOEXCEPTION (NOTCONNECTED, IS_NOT_CONNECTED); |
| } |
| |
| static |
| void (**actionptr)( void ); |
| static |
| void (*readactions[])( void ) = { inpconv, inpedit, inpioctrl }; |
| static |
| void (*writeactions[])( void ) = { outconv, outedit, outioctrl }; |
| |
| |
| static |
| void emitstr( char* begtxt, char* endtxt ) |
| { |
| char c; |
| int nchars = endtxt - begtxt; |
| if( actual_index + nchars > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW ); |
| memcpy( iostrptr + actual_index, begtxt, nchars ); |
| actual_index += nchars; |
| if( actual_index > maximum_index ) |
| maximum_index = actual_index; |
| } |
| |
| static |
| void scanstr( char* begtxt, char* endtxt ) |
| { |
| int nchars = endtxt - begtxt; |
| if( actual_index + nchars > iostrlen ) |
| IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_TEXT ); |
| if( strncmp( iostrptr + actual_index, begtxt, nchars ) ) |
| IOEXCEPTION( TEXTFAIL, FORMAT_TEXT_MISMATCH ); |
| actual_index += nchars; |
| } |
| |
| void (*ftextptr) ( char*, char* ); |
| |
| static |
| formatexit_t scanformcont( char* fcs, int len, |
| char** fcsptr, int* lenptr ) |
| { |
| char curr; |
| fcsstate_t state = FormatText; |
| unsigned long buf; |
| int dig; |
| acttype_t action; |
| char* begtxt = fcs; |
| |
| while( len-- ) |
| { |
| curr = *fcs++; |
| switch( state ) |
| { |
| case FormatText: |
| if( curr == '%' ) |
| { |
| ftextptr( begtxt, fcs-1 ); |
| state = FirstPercent; |
| } |
| break; |
| |
| after_first_percent: ; |
| case FirstPercent: |
| if( curr == '%' ) |
| { |
| state = FormatText; |
| begtxt = fcs - 1; |
| break; |
| } |
| if( curr == ')' ) |
| { |
| *lenptr = len; |
| *fcsptr = fcs; |
| return EndAtParen; |
| } |
| if( isDEC(curr) ) |
| { |
| state = RepFact; |
| repetition = curr - '0'; |
| break; |
| } |
| |
| repetition = 1; |
| |
| test_for_control_codes: ; |
| if( isCVC(curr) ) |
| { |
| state = ConvClause; |
| action = ConvAct; |
| convcode = strchr( CONVERSIONCODES, curr ) - CONVERSIONCODES; |
| leftadjust = False; |
| overflowev = False; |
| dynamicwid = False; |
| paddingdef = False; |
| paddingchar = ' '; |
| fractiondef = False; |
| /* fractionwidth = 0; default depends on mode ! */ |
| exponentdef = False; |
| exponentwidth = 3; |
| clausewidth = 0; |
| break; |
| } |
| if( isEDC(curr) ) |
| { |
| state = EditClause; |
| action = EditAct; |
| editcode = strchr( EDITCODES, curr ) - EDITCODES; |
| dynamicwid = False; |
| clausewidth = editcode == Tabulation ? 0 : 1; |
| break; |
| } |
| if( isIOC(curr) ) |
| { |
| state = ClauseEnd; |
| action = IOAct; |
| iocode = strchr( IOCODES, curr ) - IOCODES; |
| break; |
| } |
| if( curr == '(' ) |
| { |
| unsigned long times = repetition; |
| int cntlen; |
| char* cntfcs; |
| while( times-- ) |
| { |
| if( scanformcont( fcs, len, &cntfcs, &cntlen ) != EndAtParen ) |
| IOEXCEPTION( TEXTFAIL, UNMATCHED_OPENING_PAREN ); |
| } |
| fcs = cntfcs; |
| len = cntlen; |
| state = FormatText; |
| begtxt = fcs; |
| break; |
| } |
| IOEXCEPTION( TEXTFAIL, BAD_FORMAT_SPEC_CHAR ); |
| |
| case RepFact: |
| if( isDEC(curr) ) |
| { |
| dig = curr - '0'; |
| if( repetition > (ULONG_MAX - dig)/10 ) |
| IOEXCEPTION( TEXTFAIL, REPFAC_OVERFLOW ); |
| repetition = repetition*10 + dig; |
| break; |
| } |
| goto test_for_control_codes; |
| |
| case ConvClause: |
| if( isDEC(curr) ) |
| { |
| state = ClauseWidth; |
| clausewidth = curr - '0'; |
| break; |
| } |
| if( curr == 'L' ) |
| { |
| if( leftadjust ) |
| IOEXCEPTION( TEXTFAIL, DUPLICATE_QUALIFIER ); |
| leftadjust = True; |
| break; |
| } |
| if( curr == 'E' ) |
| { |
| if( overflowev ) |
| IOEXCEPTION( TEXTFAIL, DUPLICATE_QUALIFIER ); |
| overflowev = True; |
| break; |
| } |
| if( curr == 'P' ) |
| { |
| if( paddingdef ) |
| IOEXCEPTION( TEXTFAIL, DUPLICATE_QUALIFIER ); |
| paddingdef = True; |
| state = CatchPadding; |
| break; |
| } |
| |
| test_for_variable_width: ; |
| if( curr == 'V' ) |
| { |
| dynamicwid = True; |
| state = AfterWidth; |
| break; |
| } |
| goto test_for_fraction_width; |
| |
| case ClauseWidth: |
| if( isDEC(curr) ) |
| { |
| dig = curr - '0'; |
| if( clausewidth > (ULONG_MAX - dig)/10 ) |
| IOEXCEPTION( TEXTFAIL, CLAUSE_WIDTH_OVERFLOW ); |
| clausewidth = clausewidth*10 + dig; |
| break; |
| } |
| /* fall through */ |
| |
| test_for_fraction_width: ; |
| case AfterWidth: |
| if( curr == '.' ) |
| { |
| if( convcode != DefaultConv && convcode != ScientConv ) |
| IOEXCEPTION( TEXTFAIL, NO_FRACTION ); |
| fractiondef = True; |
| state = FractWidth; |
| break; |
| } |
| goto test_for_exponent_width; |
| |
| case FractWidth: |
| if( isDEC( curr ) ) |
| { |
| state = FractWidthCont; |
| fractionwidth = curr - '0'; |
| break; |
| } |
| else |
| IOEXCEPTION( TEXTFAIL, NO_FRACTION_WIDTH ); |
| |
| case FractWidthCont: |
| if( isDEC( curr ) ) |
| { |
| dig = curr - '0'; |
| if( fractionwidth > (ULONG_MAX - dig)/10 ) |
| IOEXCEPTION( TEXTFAIL, FRACTION_WIDTH_OVERFLOW ); |
| fractionwidth = fractionwidth*10 + dig; |
| break; |
| } |
| |
| test_for_exponent_width: ; |
| if( curr == ':' ) |
| { |
| if( convcode != ScientConv ) |
| IOEXCEPTION( TEXTFAIL, NO_EXPONENT ); |
| exponentdef = True; |
| state = ExpoWidth; |
| break; |
| } |
| goto test_for_final_percent; |
| |
| case ExpoWidth: |
| if( isDEC( curr ) ) |
| { |
| state = ExpoWidthCont; |
| exponentwidth = curr - '0'; |
| break; |
| } |
| else |
| IOEXCEPTION( TEXTFAIL, NO_EXPONENT_WIDTH ); |
| |
| case ExpoWidthCont: |
| if( isDEC( curr ) ) |
| { |
| dig = curr - '0'; |
| if( exponentwidth > (ULONG_MAX - dig)/10 ) |
| IOEXCEPTION( TEXTFAIL, EXPONENT_WIDTH_OVERFLOW ); |
| exponentwidth = exponentwidth*10 + dig; |
| break; |
| } |
| /* fall through */ |
| |
| test_for_final_percent: ; |
| case ClauseEnd: |
| if( curr == '%' ) |
| { |
| state = LastPercent; |
| break; |
| } |
| |
| do_the_action: ; |
| actionptr[action](); |
| state = FormatText; |
| begtxt = fcs - 1; |
| break; |
| |
| case CatchPadding: |
| paddingchar = curr; |
| state = ConvClause; |
| break; |
| |
| case EditClause: |
| if( isDEC(curr) ) |
| { |
| state = ClauseWidth; |
| clausewidth = curr - '0'; |
| break; |
| } |
| goto test_for_variable_width; |
| |
| case LastPercent: |
| actionptr[action](); |
| if( curr == '.' ) |
| { |
| state = FormatText; |
| begtxt = fcs; |
| break; |
| } |
| goto after_first_percent; |
| |
| default: |
| IOEXCEPTION( TEXTFAIL, INTERNAL_ERROR ); |
| } |
| } |
| switch( state ) |
| { |
| case FormatText: |
| ftextptr( begtxt, fcs ); |
| break; |
| case FirstPercent: |
| case LastPercent: |
| case RepFact: |
| case FractWidth: |
| case ExpoWidth: |
| IOEXCEPTION( TEXTFAIL, BAD_FORMAT_SPEC_CHAR ); |
| case CatchPadding: |
| IOEXCEPTION( TEXTFAIL, NO_PAD_CHAR ); |
| default: |
| actionptr[action](); |
| } |
| |
| *lenptr = len; |
| *fcsptr = fcs; |
| return NormalEnd; |
| } |
| |
| static |
| void |
| __read_format (char* fmtptr, |
| int fmtlen, |
| __tmp_IO_list* ioptr, |
| int iolen, |
| void* inpptr, |
| int inplen ) |
| { |
| formatexit_t res; |
| unsigned short l; |
| |
| iostrptr = (char*)inpptr; |
| iostrlen = inplen; |
| |
| /* initialisation */ |
| iolist_index = 0; |
| iolistptr = ioptr; |
| iolistlen = iolen; |
| |
| actionptr = readactions; |
| ftextptr = scanstr; |
| |
| if( (res = scanformcont( fmtptr, fmtlen, &fmtptr, &fmtlen )) == EndAtParen ) |
| IOEXCEPTION( TEXTFAIL, UNMATCHED_CLOSING_PAREN ); |
| |
| if( iolist_index != iolen ) |
| IOEXCEPTION( TEXTFAIL, EXCESS_IOLIST_ELEMENTS ); |
| |
| return; |
| } |
| |
| void |
| __readtext_f( Text_Mode* the_text_loc, |
| signed long the_index, |
| char* fmtptr, |
| int fmtlen, |
| __tmp_IO_list* ioptr, |
| int iolen, |
| char* file, |
| int line ) |
| { |
| unsigned long info; |
| |
| if( (info = setjmp( __io_exception )) ) |
| CHILLEXCEPTION( file, line, info>>16, info & 0xffff ); |
| |
| textptr = the_text_loc; |
| textrecptr = textptr->text_record; |
| actual_index = textptr->actual_index; |
| textindex = the_index; |
| |
| __read_format ( fmtptr, fmtlen, ioptr, iolen, |
| (char*)textrecptr + 2, textptr->text_record->len ); |
| textptr->actual_index = actual_index; |
| } |
| |
| void |
| __readtext_s( void* string_ptr, |
| int string_len, |
| char* fmtptr, |
| int fmtlen, |
| __tmp_IO_list* ioptr, |
| int iolen, |
| char* file, |
| int line ) |
| { |
| int info; |
| |
| if( (info = setjmp( __io_exception )) ) |
| CHILLEXCEPTION( file, line, info>>16, info & 0xffff ); |
| |
| textptr = NULL; |
| actual_index = 0; |
| |
| __read_format ( fmtptr, fmtlen, ioptr, iolen, string_ptr, string_len ); |
| } |
| |
| static |
| void |
| __write_format (char* fmtptr, |
| int fmtlen, |
| __tmp_IO_list* ioptr, |
| int iolen, |
| void* outptr, |
| int outlen ) |
| { |
| formatexit_t res; |
| unsigned short l; |
| |
| /* initialisation */ |
| maximum_index = actual_index; |
| iolist_index = 0; |
| |
| actionptr = writeactions; |
| ftextptr = emitstr; |
| iolistptr = ioptr; |
| iolistlen = iolen; |
| iostrptr = (char *)outptr + 2; |
| iostrlen = outlen; |
| |
| if( (res = scanformcont( fmtptr, fmtlen, &fmtptr, &fmtlen )) == EndAtParen ) |
| IOEXCEPTION( TEXTFAIL, UNMATCHED_CLOSING_PAREN ); |
| |
| if( iolist_index != iolen ) |
| IOEXCEPTION( TEXTFAIL, EXCESS_IOLIST_ELEMENTS ); |
| |
| /* set length of output string */ |
| #if _TEXTIO_DEBUG_ |
| printf( "maximum index = %d\n", maximum_index ); |
| #endif |
| l = maximum_index; |
| MOV2(outptr,&l); |
| return; |
| } |
| |
| void |
| __writetext_f( Text_Mode* the_text_loc, |
| signed long the_index, |
| char* fmtptr, |
| int fmtlen, |
| __tmp_IO_list* ioptr, |
| int iolen, |
| char* file, |
| int line ) |
| { |
| int info; |
| |
| if( (info = setjmp( __io_exception )) ) |
| CHILLEXCEPTION( file, line, info>>16, info & 0xffff ); |
| |
| textptr = the_text_loc; |
| textrecptr = the_text_loc->text_record; |
| textindex = the_index; |
| iolistptr = ioptr; |
| iolistlen = iolen; |
| |
| actual_index = textptr->actual_index; |
| __write_format ( fmtptr, fmtlen, ioptr, iolen, |
| textrecptr, textptr->access_sub->reclength - 2 ); |
| textptr->actual_index = actual_index; |
| } |
| |
| void |
| __writetext_s( void* string_ptr, |
| int string_len, |
| char* fmtptr, |
| int fmtlen, |
| __tmp_IO_list* ioptr, |
| int iolen, |
| char* file, |
| int line ) |
| { |
| int info; |
| |
| if( (info = setjmp( __io_exception )) ) |
| CHILLEXCEPTION( file, line, info>>16, info & 0xffff ); |
| |
| textptr = NULL; |
| actual_index = 0; |
| |
| __write_format ( fmtptr, fmtlen, ioptr, iolen, string_ptr, string_len ); |
| } |