1/* Implement Input/Output runtime actions for CHILL.
2   Copyright (C) 1992,1993 Free Software Foundation, Inc.
3   Author: Wilfried Moser, et al
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING.  If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA.  */
21
22/* As a special exception, if you link this library with other files,
23   some of which are compiled with GCC, to produce an executable,
24   this library does not by itself cause the resulting executable
25   to be covered by the GNU General Public License.
26   This exception does not however invalidate any other reasons why
27   the executable file might be covered by the GNU General Public License.  */
28
29#include <limits.h>
30#include <string.h>
31#include <ctype.h>
32#include <setjmp.h>
33#include <float.h>
34#include <math.h>
35#include <stdlib.h>
36#if _TEXTIO_DEBUG_
37#include <stdio.h>
38#endif
39
40#include "bitstring.h"
41#include "auxtypes.h"
42#include "iomodes.h"
43#include "format.h"
44#include "fileio.h"
45#include "ioerror.h"
46
47#define CH_BYTE_MIN   0xffffff80L
48#define CH_BYTE_MAX   0x0000007fL
49#define CH_UBYTE_MAX  0x000000ffUL
50#define CH_INT_MIN    0xffff8000L
51#define CH_INT_MAX    0x00007fffL
52#define CH_UINT_MAX   0x0000ffffUL
53#define CH_LONG_MIN   0x80000000L
54#define CH_LONG_MAX   0x7fffffffL
55#define CH_ULONG_MAX  0xffffffffUL
56
57#ifndef M_LN2
58#define M_LN2   0.69314718055994530942
59#endif
60#ifndef M_LN10
61#define M_LN10          2.30258509299404568402
62#endif
63
64#define DMANTDIGS  (1 + (int)(DBL_MANT_DIG * M_LN2 / M_LN10))
65#define FMANTDIGS  (1 + (int)(FLT_MANT_DIG * M_LN2 / M_LN10))
66
67/* float register length */
68#define MAXPREC 40
69
70#define LET 0x0001
71#define BIN 0x0002
72#define DEC 0x0004
73#define OCT 0x0008
74#define HEX 0x0010
75#define USC 0x0020
76#define BIL 0x0040
77#define SPC 0x0080
78#define SCS 0x0100
79#define IOC 0x0200
80#define EDC 0x0400
81#define CVC 0x0800
82
83#define isDEC(c)  ( chartab[(c)] & DEC )
84#define isCVC(c)  ( chartab[(c)] & CVC )
85#define isEDC(c)  ( chartab[(c)] & EDC )
86#define isIOC(c)  ( chartab[(c)] & IOC )
87#define isUSC(c)
88#define isXXX(c,XXX)  ( chartab[(c)] & XXX )
89
90/*
91 *  local definitions
92 */
93
94static
95short int chartab[256] = {
96  0, 0, 0, 0, 0, 0, 0, 0,
97  0, SPC, SPC, SPC, SPC, SPC, 0, 0,
98
99  0, 0, 0, 0, 0, 0, 0, 0,
100  0, 0, 0, 0, 0, 0, 0, 0,
101
102  SPC, IOC, 0, 0, 0, 0, 0, 0,
103  SCS, SCS, SCS, SCS+IOC, SCS, SCS+IOC, SCS, SCS+IOC,
104  BIN+OCT+DEC+HEX, BIN+OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX,
105     OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX,
106  DEC+HEX, DEC+HEX, SCS, SCS, SCS+EDC, SCS+IOC, SCS+EDC, IOC,
107
108  0, LET+HEX+BIL, LET+HEX+BIL+CVC, LET+HEX+BIL+CVC, LET+HEX+BIL, LET+HEX,
109     LET+HEX+CVC, LET,
110  LET+BIL+CVC, LET, LET, LET, LET, LET, LET, LET+CVC,
111
112  LET, LET, LET, LET, LET+EDC, LET, LET, LET,
113  LET+EDC, LET, LET, SCS, 0, SCS, 0, USC,
114
115  0, LET+HEX, LET+HEX, LET+HEX, LET+HEX, LET+HEX, LET+HEX, LET,
116  LET, LET, LET, LET, LET, LET, LET, LET,
117
118  LET, LET, LET, LET, LET, LET, LET, LET,
119  LET, LET, LET, 0, 0, 0, 0, 0
120};
121
122typedef enum {
123  FormatText, FirstPercent, RepFact, ConvClause, EditClause, ClauseEnd,
124  AfterWidth, FractWidth, FractWidthCont, ExpoWidth, ExpoWidthCont,
125  ClauseWidth, CatchPadding, LastPercent
126} fcsstate_t;
127
128#define CONVERSIONCODES "CHOBF"
129typedef enum {
130  DefaultConv, HexConv, OctalConv, BinaryConv, ScientConv
131} convcode_t;
132
133static
134short int base[4] = { 10, 16, 8, 2 };
135
136static
137short int dset[4] = { DEC, HEX, OCT, BIN };
138
139#define EDITCODES "X<>T"
140typedef enum {
141  SpaceSkip, SkipLeft, SkipRight, Tabulation
142} editcode_t;
143
144#define IOCODES "/+-?!="
145typedef enum {
146  NextRecord, NextPage, CurrentLine, Prompt, Emit, EndPage
147} iocode_t;
148
149typedef enum {
150  ConvAct, EditAct, IOAct
151} acttype_t;
152
153typedef enum {
154  NormalEnd, EndAtParen, TextFailEnd
155} formatexit_t;
156
157static
158double ep_1[10] = {
159  1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 };
160static
161double ep_10[10] = {
162  1e0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 };
163static
164double ep_100 = 1e100;
165
166/* float register */
167static
168unsigned char floatdig[MAXPREC];
169
170/*
171 *  global io variables
172 */
173
174static Text_Mode*      textptr = NULL;
175static VarString*      textrecptr;
176
177static int             actual_index;
178static int             maximum_index;
179static int             iolist_index;
180
181static __tmp_IO_list*  iolistptr;
182static int             iolistlen;
183static char*           iostrptr;
184static int             iostrlen;
185
186
187static convcode_t     convcode;
188static editcode_t     editcode;
189static iocode_t       iocode;
190static unsigned long  repetition;
191static Boolean        leftadjust;
192static Boolean        overflowev;
193static Boolean        dynamicwid;
194static Boolean        paddingdef;
195static char           paddingchar;
196static Boolean        fractiondef;
197static unsigned long  fractionwidth;
198static Boolean        exponentdef;
199static unsigned long  exponentwidth;
200static unsigned long  clausewidth;
201static signed long    textindex;
202
203static
204__tmp_IO_enum_table_type bool_tab[] =
205   { { 0, "FALSE" },
206     { 1, "TRUE"  },
207     { 0 , NULL   }  };
208
209/*
210 * case insensitive compare: s1 is zero delimited, s2 has n chars
211 */
212static
213int casncmp( const char* s1, const char* s2, int n )
214{
215  int res = 0;
216  while( n-- )
217  {
218    if( (res = toupper(*s1++) - toupper(*s2++)) )
219      return res;
220  }
221  return *s1;
222}
223
224/*
225 * skip spaces with blank equal to tab
226 */
227static
228int skip_space( int limit )
229{
230  int skipped = 0;
231  while( actual_index < limit &&
232         (iostrptr[actual_index] == ' ' || iostrptr[actual_index] == '\t' ) )
233  {
234    actual_index++;
235    skipped++;
236  }
237  return skipped;
238}
239
240/*
241 * skip leading pad characters
242 */
243static
244int skip_pad( int limit )
245{
246  int skipped = 0;
247  while( actual_index < limit && iostrptr[actual_index] == paddingchar )
248  {
249    actual_index++;
250    skipped++;
251  }
252#if _TEXTIO_DEBUG_
253  printf( "skipping '%c' until %d: %d\n", paddingchar, limit, skipped );
254#endif
255  return skipped;
256}
257
258/*
259 * backup trailing pad characters
260 */
261static
262int piks_pad( int start, int limit )
263{
264  int skipped = 0;
265  while( start >/***=*/ limit && iostrptr[--start] == paddingchar )
266  {
267    skipped++;
268  }
269#if _TEXTIO_DEBUG_
270  printf( "piksing '%c' from %d until %d: %d\n",
271          paddingchar, start, limit, skipped );
272#endif
273  return skipped;
274}
275
276/*
277 * parse an integer
278 */
279static
280int parse_int( int limit, int SET, int base,
281               unsigned long* valptr, int* signptr )
282{
283  int           parsed = actual_index;
284  Boolean       digits = False;
285  unsigned long value  = 0;
286  char          curr;
287  int           dig;
288
289  if( actual_index >= limit )
290    IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_INT );
291  *signptr = +1;
292  if( iostrptr[actual_index] == '+' )
293    actual_index++;
294  else
295    if( iostrptr[actual_index] == '-' )
296    {  *signptr = -1;
297       actual_index++;
298    }
299
300  for( ; actual_index < limit; actual_index++ )
301  {
302    curr = iostrptr[actual_index];
303    if( curr == '_' ) continue;
304    if( isXXX(curr,SET) )
305    {
306      digits = True;
307      dig = curr <= '9' ? curr - '0' : toupper(curr) - 'A' + 10;
308      if( value > (ULONG_MAX - dig)/base )
309        IOEXCEPTION( TEXTFAIL, INT_VAL_OVERFLOW );
310      value = value*base + dig;
311      continue;
312    }
313    break;
314  }
315  if( !digits )
316    IOEXCEPTION( TEXTFAIL, NO_DIGITS_FOR_INT );
317
318  *valptr = value;
319#if _TEXTIO_DEBUG_
320  printf( "parsing for int until %d, base %d: %u\n", limit, base, value );
321#endif
322  return actual_index - parsed;
323}
324
325static
326double
327make_float( int dexp, int sign )
328{
329  double value = atof( floatdig );
330#if _TEXTIO_DEBUG_
331  printf( " value = %25.20e, dexp = %d\n", value, dexp );
332#endif
333  while( dexp >= 100 )
334    value *= ep_100, dexp -= 100;
335  if( dexp >= 10 )
336    value *= ep_10[dexp/10], dexp %= 10;
337  if( dexp > 0 )
338    value *= ep_1[dexp];
339
340  while( dexp <= -100 )
341    value /= ep_100, dexp += 100;
342  if( dexp <= -10 )
343    value /= ep_10[-dexp/10], dexp %= 10;
344  if( dexp < 0 )
345    value /= ep_1[-dexp];
346
347  return  sign ? -value : value;
348}
349
350/* %C -> fixed point   [+|-]<digit>+[.<digit>*]  */
351static
352int parse_fixedpoint( int limit, double* valptr )
353{
354  int           parsed = actual_index;
355  Boolean       digits = False;
356  int           sdig = 0;
357  double        value;
358  char          curr;
359  int           sign = False;
360  int           expo = 0;
361
362  if( actual_index >= limit )
363    IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_FLOAT );
364  if( iostrptr[actual_index] == '+' )
365    actual_index++;
366  else
367    if( iostrptr[actual_index] == '-' )
368    {
369       sign = True;
370       actual_index++;
371    }
372
373  floatdig[0] = '.';
374  for( ; actual_index < limit; actual_index++ )
375  {
376    curr = iostrptr[actual_index];
377    if( ! isDEC(curr) )
378      break;
379    digits = True;
380    if( sdig < MAXPREC - 1 )
381    {
382      if( sdig || curr != '0' )
383      {
384        floatdig[++sdig] = curr;
385        expo++;
386      }
387    }
388    else
389      if( sdig )
390        expo++;
391  }
392  if( digits && curr == '.' )
393  {
394    actual_index++;
395    for( ; actual_index < limit; actual_index++ )
396    {
397      curr = iostrptr[actual_index];
398      if( !isDEC(curr) )
399        break;
400      if( sdig < MAXPREC - 1 )
401      {
402        if( sdig || curr != '0' )
403          floatdig[++sdig] = curr;
404        else
405          expo--;
406      }
407    }
408  }
409  floatdig[++sdig] = '\0';
410
411  if( !digits )
412    IOEXCEPTION( TEXTFAIL, NO_DIGITS_FOR_FLOAT );
413
414  *valptr = make_float( expo, sign);
415  return actual_index - parsed;
416}
417
418
419typedef enum {
420  s_sign, s_dig, s_period, s_fraca, s_fracb, s_expo, s_exposign,
421  s_expoa, s_expob }
422scient_t;
423
424/* %C -> scientific   [+|-]<digit>[.<digit>*]E[=|-]<digit>+  */
425static
426int parse_scientific( int limit, double* valptr, double dmin, double dmax )
427{
428  int           parsed = actual_index;
429  int           sdig = 0;
430  char          curr;
431  double        value;
432  int           sign = False;
433  int           expo = 0;
434  int           expo_sign = +1;
435
436  scient_t      state = s_sign;
437
438  if( actual_index >= limit )
439    IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_FLOAT );
440
441  floatdig[0] = '.';
442  for( ; actual_index < limit; actual_index++ )
443  {
444    curr = iostrptr[actual_index];
445    switch( state )
446    {
447    case s_sign:
448      if( iostrptr[actual_index] == '+' )
449      {
450        state = s_dig;
451        break;
452      }
453      if( iostrptr[actual_index] == '-' )
454      {
455        sign = True;
456        state = s_dig;
457        break;
458      }
459      /* fall through - no break */
460    case s_dig:
461      if( isDEC(curr) && curr > '0' )
462      {
463        floatdig[++sdig] = curr;
464        state = s_period;
465        break;
466      }
467      IOEXCEPTION( TEXTFAIL, NO_DIGITS_FOR_FLOAT );
468    case s_period:
469      if( curr == '.' )
470      {
471        state = s_fraca;
472        break;
473      }
474      if( curr == 'E' )
475      {
476        state = s_exposign;
477        break;
478      }
479      IOEXCEPTION( TEXTFAIL, NO_EXPONENT );
480    case s_fraca:
481      if( isDEC(curr) )
482      {
483        floatdig[++sdig] = curr;
484        state = s_fracb;
485        break;
486      }
487      IOEXCEPTION( TEXTFAIL, NO_DIGITS_FOR_FLOAT );
488    case s_fracb:
489      if( isDEC(curr) )
490      {
491        if( sdig < MAXPREC - 1 )
492          floatdig[++sdig] = curr;
493        break;
494      }
495      if( curr == 'E' )
496      {
497        state = s_exposign;
498        break;
499      }
500      IOEXCEPTION( TEXTFAIL, NO_EXPONENT );
501    case s_exposign:
502      if( iostrptr[actual_index] == '+' )
503      {
504        state = s_expoa;
505        break;
506      }
507      if( iostrptr[actual_index] == '-' )
508      {
509        expo_sign = -1;
510        state = s_expoa;
511        break;
512      }
513    case s_expoa:
514      if( isDEC(curr) )
515      {
516        expo = curr - '0';
517        state = s_expob;
518        break;
519      }
520      IOEXCEPTION( TEXTFAIL, NO_EXPONENT );
521    case s_expob:
522      expo = expo*10 + (curr - '0');
523      if( expo > 1000 )
524        IOEXCEPTION( TEXTFAIL, REAL_OVERFLOW );
525    }
526  }
527  if( state != s_expob )
528    IOEXCEPTION( TEXTFAIL, NO_EXPONENT );
529
530  expo *= expo_sign;
531  expo++;
532
533  floatdig[++sdig] = '\0';
534
535  *valptr = make_float( expo, sign );
536  return actual_index - parsed;
537}
538
539
540static
541int parse_set( int limit, __tmp_IO_enum_table_type* tabptr,
542               unsigned long* valptr )
543{
544  int    parsed = actual_index;
545  char   curr;
546  __tmp_IO_enum_table_type* etptr;
547
548  if( actual_index >= limit )
549    IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_SET );
550
551  curr = iostrptr[actual_index];
552  if( isXXX(curr,LET+USC) )
553    actual_index++;
554  else
555    IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_SET );
556
557  for( ; actual_index < limit; actual_index++ )
558  {
559    if( ! isXXX(iostrptr[actual_index],LET+DEC+USC) )
560      break;
561  }
562
563  if( tabptr )
564     while( tabptr->name )
565     {
566       if( !casncmp( tabptr->name, &iostrptr[parsed], actual_index-parsed ) )
567       {
568         *valptr = tabptr->value;
569#if _TEXTIO_DEBUG_
570         printf( "parsing set value until %d: %u\n", limit, tabptr->value );
571#endif
572         return actual_index - parsed;
573       }
574       tabptr++;
575     }
576  IOEXCEPTION( TEXTFAIL, SET_CONVERSION_ERROR );
577}
578
579static
580int parse_bit( int limit, char* bitptr )
581{
582  int parsed = actual_index;
583  int i = 0;
584  char curr;
585
586  if( actual_index >= limit )
587    IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_BOOLS );
588
589  for( ; actual_index < limit; actual_index++ )
590  {
591    curr = iostrptr[actual_index] - '0';
592    if( curr == 0 || curr == 1 )
593      /* __setbitinset( i++, bitptr, limit, curr ); */
594      __setbitpowerset (bitptr, limit, 0, i++, curr, __FILE__, __LINE__);
595    else
596      break;
597  }
598  return actual_index - parsed;
599}
600
601static
602char* myultoa( unsigned long ul, char* buf, int base )
603{
604  char*         res = buf;
605  unsigned long h = ul/base;
606  unsigned long q = 1;
607
608  while( h >= q ) q *= base;
609  while( q > 0 )
610  {
611    *buf++ = "0123456789ABCDEF"[ul/q];
612    ul %= q;
613    q /= base;
614  }
615  *buf++ = '\0';
616  return res;
617}
618
619/*
620 *  convert a bit string from src, bit offset up to len
621 */
622static
623char* bitput( char* dst, char* src, int offset, int len )
624{
625  char* res = dst;
626  int i;
627  for( i = offset; i < len; i++ )
628  {
629    *dst++ = __inpowerset( i, src, len, 0 ) ? '1' : '0';
630  }
631  return res;
632}
633
634/*
635 * dround: round decimal register *digptr starting at digit mdigs,
636 *         on carry advance begin of digit sequence and bump exponent
637 */
638static
639char*
640dround( char* digptr, int mdigs, int* deptr )
641{
642  int carry;
643#if _TEXTIO_DEBUG_
644  printf( "Rounding from %d\n", mdigs );
645#endif
646  if( digptr[mdigs] >= 5 )
647  {
648    carry = 1;
649    while( carry )
650    {
651      digptr[--mdigs]++;
652      if( digptr[mdigs] >= 10 )
653        digptr[mdigs] = 0;
654      else
655        carry = 0;
656    }
657  }
658  if( mdigs < 0 )
659  {
660    digptr[--mdigs] = 1;
661    (*deptr)++;
662    return digptr - 1;
663  }
664  else
665    return digptr;
666}
667
668/*
669 * mydtoa: convert val with a precision of mantdigs to a decimal fraction
670 *         first digit is at **fstdiptr, decimal exponent is at *deptr
671 */
672static
673char*
674mydtoa( double val, int mantdigs, int* deptr, int* sgnptr )
675{
676  double m;
677  int be;
678  int de = -1;
679  int fstdig = 0;
680  int idig;
681  char* digptr = floatdig+2;
682
683  floatdig[0] = floatdig[1] = 0;
684
685  if( val < 0 )
686    *sgnptr = -1, val = fabs( val );
687  else
688    *sgnptr = +1;
689
690  /* split the value */
691  m = frexp( val, &be ) * 10.0;
692
693  /* 5.0 <= m < 10.0 */
694  while( be > 0 )
695  {
696    de++; be--; m /= 5.0;
697    if( m < 1.0 )
698      m *= 10.0, de--;
699  }
700  while( be < 0 )
701  {
702    de--; be++; m *= 5.0;
703    if( m >= 10.0 )
704      m /= 10.0, de++;
705  }
706
707  for( idig = 0; idig < mantdigs; idig++ )
708  {
709    digptr[idig] = (int)m;
710    m = (m - digptr[idig])*10.0;
711  }
712  digptr[idig] = (int)m;
713
714  *deptr = de;
715  return dround( digptr, mantdigs, deptr );
716}
717
718#define PUT(c) \
719  { if( ifst <= ++iprt && iprt <= ilst ) *dst++ = c; }
720
721static
722char*
723fixput( char* dst, char* src,
724        int ifst, int ilst,
725        int sign, int fst, int lst,
726        int nid, int nfd )
727{
728  char* dstsav = dst;
729  int idig;
730  int iprt = 0;
731
732  if( sign < 0 )
733    PUT( '-' );
734  for( idig = nid; idig >= -nfd; idig-- )
735  {
736    if (idig == -1)
737      PUT( '.' );
738    PUT( idig > fst || lst >= idig ? '0': '0' + *src++ );
739  }
740  return dstsav;
741}
742
743static
744char*
745sciput( char* dst, char* src, char* expbeg,
746        int ifst, int ilst,
747        int sign, int de, int expwid )
748{
749  char* dstsav = dst;
750  int iprt = 0;
751  int nfd = fractionwidth;
752  int explen = strlen( expbeg );
753
754  if( sign < 0 )
755    PUT( '-' );
756  PUT( '0' + *src++ );
757  PUT( '.' );
758
759  while( nfd-- )
760    PUT( '0' + *src++ );
761  PUT( 'E' );
762  PUT( de >= 0 ? '+' : '-' );
763  while( expwid > explen )
764  {
765    PUT( '0' );
766    expwid--;
767  }
768  while( explen-- )
769    PUT( *expbeg++ );
770  return dstsav;
771}
772
773/*
774 *  handle dynamic field width
775 */
776static
777get_field_width( void )
778{
779  unsigned long  width;
780  unsigned long  ulongval;
781           long  longval;
782  __tmp_IO_list  io;
783
784
785  if( ++iolist_index > iolistlen )
786    IOEXCEPTION( TEXTFAIL, IOLIST_EXHAUSTED );
787
788  io = *iolistptr++;
789
790  /* must be integer, >= 0 */
791  switch( io.__descr )
792  {
793  case __IO_ByteVal:
794    longval = io.__t.__valbyte;
795    goto signed_fieldwidth;
796  case __IO_UByteVal:
797    width = io.__t.__valubyte;
798    goto unsigned_fieldwidth;
799  case __IO_IntVal:
800    longval = io.__t.__valint;
801    goto signed_fieldwidth;
802  case __IO_UIntVal:
803    width = io.__t.__valuint;
804    goto unsigned_fieldwidth;
805  case __IO_LongVal:
806    longval = io.__t.__vallong;
807    goto signed_fieldwidth;
808  case __IO_ULongVal:
809    width = io.__t.__valulong;
810    goto unsigned_fieldwidth;
811  case __IO_ByteLoc:
812    longval = *(signed char*)io.__t.__locint;
813    goto signed_fieldwidth;
814  case __IO_UByteLoc:
815    width = *(unsigned char*)io.__t.__locint;
816    goto unsigned_fieldwidth;
817  case __IO_IntLoc:
818    longval = *(signed short*)io.__t.__locint;
819    goto signed_fieldwidth;
820  case __IO_UIntLoc:
821    width = *(unsigned short*)io.__t.__locint;
822    goto unsigned_fieldwidth;
823  case __IO_LongLoc:
824    longval = *(signed long*) io.__t.__locint;
825    goto signed_fieldwidth;
826  case __IO_ULongLoc:
827    width = *(unsigned long*)io.__t.__locint;
828    goto unsigned_fieldwidth;
829  default:
830    IOEXCEPTION( TEXTFAIL, NON_INT_FIELD_WIDTH );
831  }
832
833signed_fieldwidth: ;
834  if( longval < 0 )
835    IOEXCEPTION( TEXTFAIL, NEGATIVE_FIELD_WIDTH );
836  width = longval;
837
838unsigned_fieldwidth: ;
839  return width;
840}
841
842
843static
844void inpconv( void )
845{
846  __tmp_IO_list  io;
847  int            width;
848  int            limit;
849  int            skiplim;
850  int            skipped;
851  int            bypass;
852  int            parsed;
853  Boolean        fixedchars;
854  int            fixedlen;
855  unsigned char  curr;
856  double         dval;
857  float          fval;
858
859  __tmp_IO_long  lval;
860  int            sign;
861  unsigned long  umin;
862  unsigned long  umax;
863    signed long  smin;
864    signed long  smax;
865  int            ilen;
866  short unsigned slen;
867  __tmp_IO_enum_table_type* settabptr;
868
869  while( repetition-- )
870  {
871    if( ++iolist_index > iolistlen )
872      IOEXCEPTION( TEXTFAIL, IOLIST_EXHAUSTED );
873
874    io = *iolistptr++;
875
876    if( dynamicwid )
877      width = get_field_width();
878    else
879      width = clausewidth;
880
881    bypass = skipped = 0;
882    if( width )
883    {
884      if( actual_index + width > iostrlen )
885        IOEXCEPTION( TEXTFAIL, NOT_ENOUGH_CHARS );
886
887      switch(io.__descr)
888      {
889      case __IO_CharLoc:
890      case __IO_CharRangeLoc:
891        fixedchars = True;
892        fixedlen = 1;
893        break;
894      case __IO_CharStrLoc:
895        fixedchars = True;
896        fixedlen = io.__t.__loccharstring.string_length;
897        break;
898      default:
899        fixedchars = False;
900        break;
901      }
902
903      if( leftadjust )
904      {
905        skiplim = fixedchars ? actual_index + fixedlen
906                             : actual_index;
907        bypass = skipped = piks_pad( actual_index + width, skiplim );
908      }
909      else
910      {
911        skiplim = fixedchars ? actual_index + width - fixedlen
912                             : actual_index + width;
913        skipped = skip_pad( skiplim );
914      }
915      width -= skipped;
916      limit = actual_index + width;
917    }
918    else
919    { /* free format */
920      if( paddingdef || !( io.__descr == __IO_CharLoc ||
921                           io.__descr == __IO_CharRangeLoc ||
922                           io.__descr == __IO_CharStrLoc ||
923                           io.__descr == __IO_CharVaryingLoc ) )
924        if( paddingchar == ' ' || paddingchar == '\t' )
925          skip_space( iostrlen );
926        else
927          skip_pad( iostrlen );
928      limit = iostrlen;
929    }
930
931    switch( io.__descr )
932    {
933    case __IO_ByteLoc:
934      ilen = 1;
935      smin = CH_BYTE_MIN;
936      smax = CH_BYTE_MAX;
937      goto parse_signed_int;
938    case __IO_UByteLoc:
939      ilen = 1;
940      umin = 0;
941      umax = CH_UBYTE_MAX;
942      goto parse_unsigned_int;
943    case __IO_IntLoc:
944      ilen = 2;
945      smin = CH_INT_MIN;
946      smax = CH_INT_MAX;
947      goto parse_signed_int;
948    case __IO_UIntLoc:
949      ilen = 2;
950      umin = 0;
951      umax = CH_UINT_MAX;
952      goto parse_unsigned_int;
953    case __IO_LongLoc:
954      ilen = 4;
955      smin = CH_LONG_MIN;
956      smax = CH_LONG_MAX;
957      goto parse_signed_int;
958    case __IO_ULongLoc:
959      ilen = 4;
960      umin = 0;
961      umax = CH_ULONG_MAX;
962      goto parse_unsigned_int;
963
964    case __IO_ByteRangeLoc:
965      ilen = 1;
966      smin = io.__t.__locintrange.lower.slong;
967      smax = io.__t.__locintrange.upper.slong;
968      goto parse_signed_int;
969    case __IO_UByteRangeLoc:
970      ilen = 1;
971      umin = io.__t.__locintrange.lower.ulong;
972      umax = io.__t.__locintrange.upper.ulong;
973      goto parse_unsigned_int;
974    case __IO_IntRangeLoc:
975      ilen = 2;
976      smin = io.__t.__locintrange.lower.slong;
977      smax = io.__t.__locintrange.upper.slong;
978      goto parse_signed_int;
979    case __IO_UIntRangeLoc:
980      ilen = 2;
981      umin = io.__t.__locintrange.lower.ulong;
982      umax = io.__t.__locintrange.upper.ulong;
983      goto parse_unsigned_int;
984    case __IO_LongRangeLoc:
985      ilen = 4;
986      smin = io.__t.__locintrange.lower.slong;
987      smax = io.__t.__locintrange.upper.slong;
988      goto parse_signed_int;
989    case __IO_ULongRangeLoc:
990      ilen = 4;
991      umin = io.__t.__locintrange.lower.ulong;
992      umax = io.__t.__locintrange.upper.ulong;
993      goto parse_unsigned_int;
994
995    case __IO_BoolLoc:
996      ilen = 1;
997      umin = 0;
998      umax = 1;
999      settabptr = bool_tab;
1000      goto parse_set;
1001    case __IO_BoolRangeLoc:
1002      ilen = 1;
1003      umin = io.__t.__locboolrange.lower;
1004      umax = io.__t.__locboolrange.upper;
1005      settabptr = bool_tab;
1006      goto parse_set;
1007
1008    case __IO_SetLoc:
1009      ilen = io.__t.__locsetrange.length;
1010      settabptr = io.__t.__locsetrange.name_table;
1011      umin = 0;
1012      umax = CH_ULONG_MAX;
1013      goto parse_set;
1014    case __IO_SetRangeLoc:
1015      ilen = io.__t.__locsetrange.length;
1016      settabptr = io.__t.__locsetrange.name_table;
1017      umin = io.__t.__locsetrange.lower;
1018      umax = io.__t.__locsetrange.upper;
1019      goto parse_set;
1020
1021    case __IO_CharLoc:
1022      umin = 0;
1023      umax = 0xff;
1024      goto parse_char;
1025    case __IO_CharRangeLoc:
1026      umin = io.__t.__loccharrange.lower;
1027      umax = io.__t.__loccharrange.upper;
1028      goto parse_char;
1029
1030    case __IO_CharVaryingLoc:
1031      if( convcode != DefaultConv )
1032        IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1033      slen = io.__t.__loccharstring.string_length;
1034      if( (parsed = limit - actual_index) < slen )
1035        slen = parsed;
1036      else
1037        parsed = slen;
1038      memcpy( io.__t.__loccharstring.string + 2,
1039              &iostrptr[actual_index], parsed );
1040      MOV2(io.__t.__loccharstring.string,&slen);
1041      actual_index += parsed;
1042      goto check_field_complete;
1043
1044
1045    case __IO_CharStrLoc:
1046      if( convcode != DefaultConv )
1047        IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1048      if( actual_index + io.__t.__loccharstring.string_length > limit )
1049        IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_CHARS );
1050      memcpy( io.__t.__loccharstring.string,
1051              &iostrptr[actual_index],
1052              parsed = io.__t.__loccharstring.string_length );
1053      actual_index += parsed;
1054      goto check_field_complete;
1055
1056    case __IO_BitStrLoc:
1057      if( convcode != DefaultConv )
1058        IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1059      parsed = parse_bit( limit, io.__t.__loccharstring.string );
1060      if( parsed < io.__t.__loccharstring.string_length )
1061        IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_BOOLS );
1062      goto check_field_complete;
1063
1064    case __IO_LongRealLoc:
1065    case __IO_RealLoc:
1066      switch( convcode )
1067      {
1068      case ScientConv:
1069        parse_scientific( limit, &dval, DBL_MIN, DBL_MAX );
1070        break;
1071      case DefaultConv:
1072        parse_fixedpoint( limit, &dval );
1073        break;
1074      default:
1075        IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1076      }
1077      if( io.__descr == __IO_LongRealLoc )
1078        memcpy( io.__t.__loclongreal, &dval, sizeof(double) );
1079      else
1080      {
1081        fval = (float)dval;
1082        MOV4(io.__t.__locreal,&fval);
1083      }
1084      goto check_field_complete;
1085    default:
1086      IOEXCEPTION( TEXTFAIL, INVALID_IO_LIST );
1087    }
1088
1089
1090parse_signed_int: ;
1091    if( convcode == ScientConv )
1092      IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1093    parsed = parse_int( limit, dset[convcode], base[convcode],
1094                        &lval.ulong, &sign );
1095    if( sign < 0 )
1096    {
1097      if( lval.ulong > (unsigned long)CH_LONG_MIN )
1098        IOEXCEPTION( TEXTFAIL, INTEGER_RANGE_ERROR );
1099      lval.slong = -lval.ulong;
1100    }
1101    else
1102    {
1103      /* not needed: lval.slong = lval.ulong; */
1104      /* Hack: sign extension for bin/oct/dec if no sign present */
1105      if( convcode != DefaultConv && lval.ulong & (1 << (ilen*8-1)) )
1106      {
1107        if( ilen < 4 )
1108          lval.ulong |= 0xFFFFFFFF << ilen*8;
1109      }
1110      else
1111        if( lval.ulong > (unsigned long)CH_LONG_MAX )
1112          IOEXCEPTION( TEXTFAIL, INTEGER_RANGE_ERROR );
1113    }
1114    if( lval.slong < smin || smax < lval.slong )
1115      IOEXCEPTION( TEXTFAIL, INTEGER_RANGE_ERROR );
1116    goto store_int;
1117
1118parse_unsigned_int: ;
1119    if( convcode == ScientConv )
1120      IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1121    parsed = parse_int( limit, dset[convcode], base[convcode],
1122                        &lval.ulong, &sign );
1123    if( sign < 0 ||  lval.ulong < umin || umax < lval.ulong )
1124      IOEXCEPTION( TEXTFAIL, INTEGER_RANGE_ERROR );
1125    goto store_int;
1126
1127parse_set: ;
1128    if( convcode != DefaultConv )
1129      IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1130    parsed = parse_set( limit, settabptr, &lval.ulong );
1131    if( lval.ulong < umin || umax < lval.ulong )
1132      IOEXCEPTION( TEXTFAIL, SET_RANGE_ERROR );
1133    goto store_int;
1134
1135store_int: ;
1136    switch( ilen )
1137    {
1138    case 1:
1139      *(unsigned char*)io.__t.__locint = lval.ulong;
1140      break;
1141    case 2:
1142      slen = lval.ulong;
1143      MOV2(io.__t.__locint,&slen);
1144      break;
1145    case 4:
1146      MOV4(io.__t.__locint,&lval.ulong);
1147      break;
1148    default:
1149      IOEXCEPTION( TEXTFAIL, INTERNAL_ERROR );
1150    }
1151    goto check_field_complete;
1152
1153parse_char: ;
1154    if( convcode != DefaultConv )
1155      IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1156    if( actual_index >= limit )
1157      IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_CHARS );
1158    curr = iostrptr[actual_index++];
1159    parsed = 1;
1160    if( curr < umin || umax < curr )
1161      IOEXCEPTION( TEXTFAIL, CHAR_RANGE_ERROR );
1162    *io.__t.__locchar = curr;
1163    goto check_field_complete;
1164
1165check_field_complete: ;
1166    actual_index += bypass;
1167    if( width > parsed )
1168      IOEXCEPTION( TEXTFAIL, INVALID_CHAR );
1169  }
1170}
1171
1172static
1173void inpedit( void )
1174{
1175  int           nchars;
1176
1177  if( dynamicwid )
1178    clausewidth = get_field_width();
1179
1180  switch( editcode )
1181  {
1182  case SpaceSkip:
1183    nchars = repetition*clausewidth;
1184    if( actual_index + nchars > iostrlen )
1185      IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_EDIT );
1186    for( ; nchars ; nchars-- )
1187      if( iostrptr[actual_index++] != ' ' )
1188        IOEXCEPTION( TEXTFAIL, NO_SPACE_TO_SKIP );
1189    break;
1190
1191  case SkipLeft:
1192    nchars = repetition*clausewidth;
1193    if( (actual_index -= nchars) < 0 )
1194      IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_EDIT );
1195    break;
1196
1197  case SkipRight:
1198    nchars = repetition*clausewidth;
1199    if( (actual_index += nchars) > iostrlen )
1200      IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_EDIT );
1201    break;
1202
1203  case Tabulation:
1204    if( (actual_index = clausewidth) > iostrlen )
1205      IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1206    break;
1207  }
1208}
1209
1210static
1211void outconv( void )
1212{
1213  unsigned long             width;
1214  char                      itembuf[33];
1215  unsigned long             ulongval;
1216           long             longval;
1217  __tmp_IO_list             io;
1218  __tmp_IO_enum_table_type* etptr;
1219  char*                     itembeg;
1220  unsigned long             itemlen;
1221  double                    doubleval;
1222  int                       de;
1223  int                       sign;
1224  int                       mantdigs;
1225  int                       nid;
1226  int                       nfd;
1227  char*                     expbeg;
1228  int                       explen;
1229  unsigned int              expwid;
1230
1231  while( repetition-- )
1232  {
1233    if( ++iolist_index > iolistlen )
1234      IOEXCEPTION( TEXTFAIL, IOLIST_EXHAUSTED );
1235
1236    io = *iolistptr++;
1237    width =  dynamicwid ? get_field_width() : clausewidth;
1238
1239    switch( convcode )
1240    {
1241    case DefaultConv:
1242      switch( io.__descr )
1243      {
1244      case __IO_ByteVal:
1245        longval = io.__t.__valbyte;
1246        goto signed_conversion;
1247      case __IO_UByteVal:
1248        ulongval = io.__t.__valubyte;
1249        goto unsigned_conversion;
1250      case __IO_IntVal:
1251        longval = io.__t.__valint;
1252        goto signed_conversion;
1253      case __IO_UIntVal:
1254        ulongval = io.__t.__valuint;
1255        goto unsigned_conversion;
1256      case __IO_LongVal:
1257        longval = io.__t.__vallong;
1258        goto signed_conversion;
1259      case __IO_ULongVal:
1260        ulongval = io.__t.__valulong;
1261        goto unsigned_conversion;
1262
1263      case __IO_BoolVal:
1264        switch( io.__t.__valbool )
1265        {
1266        case 0:
1267          itembeg = "FALSE";
1268          itemlen = 5;
1269          goto move_item;
1270        case 1:
1271          itembeg = "TRUE";
1272          itemlen = 4;
1273          goto move_item;
1274        default:
1275          IOEXCEPTION( TEXTFAIL, BOOL_CONVERSION_ERROR );
1276        }
1277
1278      case __IO_CharVal:
1279        itembeg = &io.__t.__valchar;
1280        itemlen = 1;
1281        goto move_item;
1282
1283      case __IO_SetVal:
1284        /* locate name string using set mode name table */
1285        itembeg = 0;
1286
1287        if( (etptr = io.__t.__valset.name_table) )
1288          while( etptr->name )
1289	  {
1290            if( etptr->value == io.__t.__valset.value )
1291	    {
1292              itembeg = etptr->name;
1293              itemlen = strlen( itembeg );
1294              goto move_item;
1295            }
1296            etptr++;
1297          }
1298       IOEXCEPTION( TEXTFAIL, SET_CONVERSION_ERROR );
1299
1300      case __IO_CharVaryingLoc:
1301        {
1302          unsigned short l;
1303          itembeg = (char*)io.__t.__loccharstring.string;
1304          MOV2(&l,itembeg);
1305          itembeg += 2;
1306          itemlen = l;
1307          goto move_item;
1308        }
1309
1310      case __IO_CharStrLoc:
1311        itembeg = io.__t.__loccharstring.string;
1312        itemlen = io.__t.__loccharstring.string_length;
1313        goto move_item;
1314
1315      case __IO_BitStrLoc:
1316        itemlen = io.__t.__loccharstring.string_length;
1317        itembeg = io.__t.__loccharstring.string;
1318
1319        if( !width )
1320          width = itemlen;
1321
1322        /* check remaining space */
1323        if( actual_index + width > iostrlen )
1324          IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1325
1326        if( itemlen == width )
1327          bitput( iostrptr + actual_index, itembeg, 0, itemlen );
1328        else
1329          if( itemlen < width )
1330            if( leftadjust )
1331              memset( bitput( iostrptr + actual_index, itembeg, 0, itemlen )
1332                      + itemlen,
1333                      paddingchar, width - itemlen );
1334            else
1335              bitput( memset( iostrptr + actual_index,
1336                              paddingchar, width - itemlen )
1337                      + width - itemlen,
1338                      itembeg, itemlen - width, itemlen );
1339          else
1340            if( overflowev )
1341              memset( iostrptr + actual_index, '*', width );
1342            else
1343              if( leftadjust )
1344                bitput( iostrptr + actual_index, itembeg, 0, width );
1345              else
1346                bitput( iostrptr + actual_index, itembeg,
1347                        itemlen - width, itemlen );
1348        goto adjust_index;
1349
1350      case __IO_RealVal:
1351        doubleval = io.__t.__valreal;
1352        mantdigs = FMANTDIGS;
1353        goto fixed_point_conversion;
1354      case __IO_LongRealVal:
1355        doubleval = io.__t.__vallongreal;
1356        mantdigs = DBL_DIG;
1357        goto fixed_point_conversion;
1358        break;
1359
1360      default:
1361        IOEXCEPTION( TEXTFAIL, INVALID_IO_LIST );
1362      }
1363
1364    case HexConv:
1365    case OctalConv:
1366    case BinaryConv:
1367      switch( io.__descr )
1368      {
1369      case __IO_ByteVal:
1370      case __IO_UByteVal:
1371        ulongval = io.__t.__valubyte;
1372        break;
1373      case __IO_IntVal:
1374      case __IO_UIntVal:
1375        ulongval = io.__t.__valuint;
1376        break;
1377      case __IO_LongVal:
1378      case __IO_ULongVal:
1379        ulongval = io.__t.__valulong;
1380        break;
1381      default:
1382        IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1383      }
1384      itembeg = myultoa( ulongval, itembuf, base[convcode] );
1385      itemlen = strlen( itembeg );
1386      goto move_item;
1387
1388    case ScientConv:
1389      switch( io.__descr )
1390      {
1391      case __IO_RealVal:
1392        doubleval = io.__t.__valreal;
1393        mantdigs = FMANTDIGS;
1394        if( !fractiondef )
1395          fractionwidth = FMANTDIGS - 1;
1396        goto scientific_conversion;
1397      case __IO_LongRealVal:
1398        doubleval = io.__t.__vallongreal;
1399        mantdigs = DBL_DIG;
1400        if( !fractiondef )
1401          fractionwidth = DBL_DIG - 1;
1402        goto scientific_conversion;
1403        break;
1404      default:
1405        IOEXCEPTION( TEXTFAIL, CONVCODE_MODE_MISFIT );
1406      }
1407    }
1408
1409fixed_point_conversion: ;
1410    itembeg = mydtoa( doubleval, mantdigs, &de, &sign );
1411    if( fractiondef && de >= -fractionwidth - 1
1412        && -fractionwidth > de - mantdigs )
1413      itembeg = dround( itembeg, de + fractionwidth + 1, &de );
1414
1415    nid = de >= 0 ? de : 0;
1416    nfd = fractiondef ? fractionwidth
1417                      : ( de + 1 - mantdigs > 0 ? 0 : mantdigs - de - 1 );
1418    itemlen = ( sign < 0 ? 1 : 0 ) + 2 + nid + nfd;
1419#if _TEXTIO_DEBUG_
1420printf( "fixed item length %d\n", itemlen );
1421#endif
1422    if( !width )
1423      width = itemlen;
1424#if _TEXTIO_DEBUG_
1425printf( "fixed item width %d\n", width );
1426#endif
1427    /* check remaining space */
1428    if( actual_index + width > iostrlen )
1429      IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1430
1431    if( itemlen == width )
1432      fixput( iostrptr + actual_index, itembeg,
1433              1, itemlen, sign, de, de - mantdigs, nid, nfd );
1434    else
1435      if( itemlen < width )
1436        if( leftadjust )
1437          memset( fixput( iostrptr + actual_index, itembeg,
1438                          1, itemlen, sign, de, de - mantdigs, nid, nfd )
1439                  + itemlen,
1440                  paddingchar, width - itemlen );
1441        else
1442          fixput( memset( iostrptr + actual_index,
1443                          paddingchar, width - itemlen )
1444                  + width - itemlen,
1445                  itembeg, 1, itemlen, sign, de, de - mantdigs, nid, nfd );
1446      else
1447        if( overflowev )
1448          memset( iostrptr + actual_index, '*', width );
1449        else
1450          if( leftadjust )
1451            fixput( iostrptr + actual_index, itembeg,
1452                    1, width, sign, de, de - mantdigs, nid, nfd );
1453          else
1454            fixput( iostrptr + actual_index, itembeg,
1455                    itemlen - width + 1, itemlen,
1456                    sign, de, de - mantdigs, nid, nfd );
1457    goto adjust_index;
1458
1459scientific_conversion: ;
1460    itembeg = mydtoa( doubleval, mantdigs, &de, &sign );
1461
1462    if( fractiondef && fractionwidth < mantdigs )
1463      itembeg = dround( itembeg, fractionwidth + 1, &de );
1464
1465    expbeg = myultoa( abs(de), itembuf, 10 );
1466    explen = strlen( expbeg );
1467
1468    expwid = explen > exponentwidth ? explen : exponentwidth;
1469    itemlen = ( sign < 0 ? 1 : 0 ) + 2 + fractionwidth + 2 + expwid;
1470#if _TEXTIO_DEBUG_
1471printf( "floating item length %d, fraction %d, exponent %d\n",
1472        itemlen, fractionwidth, expwid );
1473#endif
1474    if( width == 0 )
1475      width = itemlen;
1476#if _TEXTIO_DEBUG_
1477printf( "floating item width %d\n", width );
1478#endif
1479    /* check remaining space */
1480    if( actual_index + width > iostrlen )
1481      IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1482
1483    if( itemlen == width )
1484      sciput( iostrptr + actual_index, itembeg, expbeg,
1485              1, itemlen, sign, de, expwid );
1486    else
1487      if( itemlen < width )
1488        if( leftadjust )
1489          memset( sciput( iostrptr + actual_index, itembeg, expbeg,
1490                          1, itemlen, sign, de, expwid )
1491                  + itemlen,
1492                  paddingchar, width - itemlen );
1493        else
1494          sciput( memset( iostrptr + actual_index,
1495                          paddingchar, width - itemlen )
1496                  + width - itemlen,
1497                  itembeg, expbeg, 1, itemlen, sign, de, expwid );
1498      else
1499        if( overflowev )
1500          memset( iostrptr + actual_index, '*', width );
1501        else
1502          if( leftadjust )
1503            sciput( iostrptr + actual_index, itembeg, expbeg,
1504                    1, width, sign, de, expwid );
1505          else
1506            sciput( iostrptr + actual_index, itembeg, expbeg,
1507                    itemlen - width + 1, itemlen,
1508                    sign, de, expwid );
1509    goto adjust_index;
1510
1511signed_conversion: ;
1512    if( longval >= 0 )
1513      itembeg = myultoa( longval, itembuf, 10 );
1514    else
1515    {
1516      itembuf[0] = '-';
1517      myultoa( -longval, itembuf+1, 10 );
1518      itembeg = itembuf;
1519    }
1520    itemlen = strlen( itembeg );
1521    goto move_item;
1522
1523unsigned_conversion: ;
1524    itembeg = myultoa( ulongval, itembuf, 10 );
1525    itemlen = strlen( itembeg );
1526    goto move_item;
1527
1528move_item: ;
1529    if( !width )
1530      width = itemlen;
1531
1532    /* check remaining space */
1533    if( actual_index + width > iostrlen )
1534      IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1535
1536    /* move item, filling or truncating or overflow-evidencing */
1537    if( itemlen == width )
1538      memcpy( iostrptr + actual_index, itembeg, itemlen );
1539    else
1540      if( itemlen < width )
1541        if( leftadjust )
1542          memset( memcpy( iostrptr + actual_index, itembeg, itemlen )
1543                  + itemlen,
1544                  paddingchar, width - itemlen );
1545        else
1546          memcpy( memset( iostrptr + actual_index,
1547                          paddingchar, width - itemlen )
1548                  + width - itemlen,
1549                  itembeg, itemlen );
1550      else
1551        if( overflowev )
1552          memset( iostrptr + actual_index, '*', width );
1553        else
1554          if( leftadjust )
1555            memcpy( iostrptr + actual_index, itembeg, width );
1556          else
1557            memcpy( iostrptr + actual_index,
1558                    itembeg + itemlen - width, width );
1559
1560  /*
1561   *  adjust.
1562   */
1563adjust_index: ;
1564  actual_index += width;
1565  if( actual_index > maximum_index )
1566    maximum_index = actual_index;
1567  }
1568}
1569
1570static
1571void outedit( void )
1572{
1573  int nchars;
1574
1575  if( dynamicwid )
1576    clausewidth = get_field_width();
1577  switch( editcode )
1578  {
1579  case SpaceSkip:
1580    nchars = repetition*clausewidth;
1581    if( actual_index + nchars > iostrlen )
1582      IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1583    memset( iostrptr + actual_index, ' ', nchars );
1584    actual_index += nchars;
1585    if( actual_index > maximum_index )
1586      maximum_index = actual_index;
1587    break;
1588
1589  case SkipLeft:
1590    nchars = repetition*clausewidth;
1591    if(  actual_index - nchars < 0 )
1592      IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1593    actual_index -= nchars;
1594    break;
1595
1596  case SkipRight:
1597    nchars = repetition*clausewidth;
1598    if( actual_index + nchars > iostrlen )
1599      IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1600    actual_index += nchars;
1601    if( actual_index > maximum_index )
1602    {
1603      memset( iostrptr + maximum_index, ' ', actual_index - maximum_index );
1604      maximum_index = actual_index;
1605    }
1606    break;
1607
1608  case Tabulation:
1609    if( clausewidth >= iostrlen )
1610      IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1611    actual_index = clausewidth;
1612    if( actual_index > maximum_index )
1613    {
1614      memset( iostrptr + maximum_index, ' ', actual_index - maximum_index );
1615      maximum_index = actual_index;
1616    }
1617    break;
1618  }
1619}
1620
1621
1622static
1623void inpioctrl( void )
1624{
1625  unsigned short hlen;
1626  if( !textptr )
1627    IOEXCEPTION( TEXTFAIL, IO_CONTROL_NOT_VALID );
1628  if( iocode != EndPage )
1629  {
1630    jmp_buf ioerror;
1631    unsigned long info;
1632
1633    if (textptr->access_sub->association)
1634      {
1635	if( (info = setjmp( ioerror )) )
1636	  IOEXCEPTION( info>>16, info & 0xffff );
1637	while( repetition-- )
1638	  {
1639	    __readrecord( textptr->access_sub, textindex,
1640			 (char*)textptr->text_record,
1641			 __FILE__, __LINE__ );
1642	    actual_index = 0;
1643	    MOV2(&hlen,&textptr->text_record->len);
1644	    iostrlen = hlen;
1645	  }
1646      }
1647    else
1648      IOEXCEPTION (NOTCONNECTED, IS_NOT_CONNECTED);
1649  }
1650}
1651
1652/* specify pre/post in the order "/+-?!" */
1653static
1654char* pre_char =  "\0\f\0\r\0"; /* Z.200: "\n\f\0\n\0" */
1655static
1656char* post_char = "\n\n\r\0\0"; /* Z.200: "\r\r\r\0\0" */
1657
1658static
1659void outioctrl( void )
1660{
1661  Association_Mode* assoc;
1662  unsigned short hlen;
1663  if( !textptr )
1664    IOEXCEPTION( TEXTFAIL, IO_CONTROL_NOT_VALID );
1665  if( (assoc = textptr->access_sub->association) )
1666  {
1667    jmp_buf ioerror;
1668    unsigned long info;
1669    if( (info = setjmp( ioerror )) )
1670      IOEXCEPTION( info>>16, info & 0xffff );
1671
1672    while( repetition-- )
1673    {
1674      if( iocode != EndPage )
1675      {
1676        if( TEST_FLAG( assoc, IO_FIRSTLINE ) )
1677        {
1678          CLR_FLAG( assoc, IO_FIRSTLINE );
1679          assoc->ctl_pre = '\0';
1680        }
1681        else
1682        {
1683          if( TEST_FLAG( assoc, IO_FORCE_PAGE ) )
1684          {
1685            CLR_FLAG( assoc, IO_FORCE_PAGE );
1686            assoc->ctl_pre = '\f';
1687	  }
1688          else
1689            assoc->ctl_pre = pre_char[iocode];
1690        }
1691        assoc->ctl_post = post_char[iocode];
1692        hlen = actual_index;
1693        MOV2(&textptr->text_record->len,&hlen);
1694        __writerecord( textptr->access_sub, textindex,
1695                       (char*)textptr->text_record,
1696                       textptr->text_record->len,
1697                       __FILE__, __LINE__ );
1698        hlen = actual_index = 0;
1699        MOV2(&textptr->text_record->len,&hlen);
1700      }
1701      else if( !TEST_FLAG( textptr, IO_FIRSTLINE ) )
1702	SET_FLAG( textptr, IO_FORCE_PAGE );
1703      assoc->ctl_pre = assoc->ctl_post = '\0';
1704    }
1705  }
1706  else
1707    IOEXCEPTION (NOTCONNECTED, IS_NOT_CONNECTED);
1708}
1709
1710static
1711void (**actionptr)( void );
1712static
1713void (*readactions[])( void ) = { inpconv, inpedit, inpioctrl };
1714static
1715void (*writeactions[])( void ) = { outconv, outedit, outioctrl };
1716
1717
1718static
1719void emitstr( char* begtxt, char* endtxt )
1720{
1721  char c;
1722  int  nchars = endtxt - begtxt;
1723  if( actual_index + nchars > iostrlen )
1724      IOEXCEPTION( TEXTFAIL, TEXT_LOC_OVERFLOW );
1725  memcpy( iostrptr + actual_index, begtxt, nchars );
1726  actual_index += nchars;
1727  if( actual_index > maximum_index )
1728    maximum_index = actual_index;
1729}
1730
1731static
1732void scanstr( char* begtxt, char* endtxt )
1733{
1734  int  nchars = endtxt - begtxt;
1735  if( actual_index + nchars > iostrlen )
1736    IOEXCEPTION( TEXTFAIL, NO_CHARS_FOR_TEXT );
1737  if( strncmp( iostrptr + actual_index, begtxt, nchars ) )
1738    IOEXCEPTION( TEXTFAIL, FORMAT_TEXT_MISMATCH );
1739  actual_index += nchars;
1740}
1741
1742void (*ftextptr) ( char*, char* );
1743
1744static
1745formatexit_t scanformcont( char* fcs, int len,
1746                           char** fcsptr, int* lenptr )
1747{
1748  char          curr;
1749  fcsstate_t    state  = FormatText;
1750  unsigned long buf;
1751  int           dig;
1752  acttype_t     action;
1753  char*         begtxt = fcs;
1754
1755  while( len-- )
1756  {
1757    curr = *fcs++;
1758    switch( state )
1759    {
1760    case FormatText:
1761      if( curr == '%' )
1762      {
1763        ftextptr( begtxt, fcs-1 );
1764        state = FirstPercent;
1765      }
1766      break;
1767
1768after_first_percent: ;
1769    case FirstPercent:
1770      if( curr == '%' )
1771      {
1772        state = FormatText;
1773        begtxt = fcs - 1;
1774        break;
1775      }
1776      if( curr == ')' )
1777      {
1778        *lenptr = len;
1779        *fcsptr = fcs;
1780        return EndAtParen;
1781      }
1782      if( isDEC(curr) )
1783      {
1784        state = RepFact;
1785        repetition = curr - '0';
1786        break;
1787      }
1788
1789      repetition = 1;
1790
1791test_for_control_codes: ;
1792      if( isCVC(curr) )
1793      {
1794        state = ConvClause;
1795        action = ConvAct;
1796        convcode = strchr( CONVERSIONCODES, curr ) - CONVERSIONCODES;
1797        leftadjust = False;
1798        overflowev = False;
1799        dynamicwid = False;
1800        paddingdef = False;
1801        paddingchar = ' ';
1802        fractiondef = False;
1803        /* fractionwidth = 0; default depends on mode ! */
1804        exponentdef = False;
1805        exponentwidth = 3;
1806        clausewidth = 0;
1807        break;
1808      }
1809      if( isEDC(curr) )
1810      {
1811        state = EditClause;
1812        action = EditAct;
1813        editcode = strchr( EDITCODES, curr ) - EDITCODES;
1814        dynamicwid = False;
1815        clausewidth = editcode == Tabulation ? 0 : 1;
1816        break;
1817      }
1818      if( isIOC(curr) )
1819      {
1820        state = ClauseEnd;
1821        action = IOAct;
1822        iocode = strchr( IOCODES, curr ) - IOCODES;
1823        break;
1824      }
1825      if( curr == '(' )
1826      {
1827        unsigned long times = repetition;
1828        int  cntlen;
1829        char* cntfcs;
1830        while( times-- )
1831        {
1832          if( scanformcont( fcs, len, &cntfcs, &cntlen ) != EndAtParen )
1833            IOEXCEPTION( TEXTFAIL, UNMATCHED_OPENING_PAREN );
1834        }
1835        fcs = cntfcs;
1836        len = cntlen;
1837        state  = FormatText;
1838        begtxt = fcs;
1839        break;
1840      }
1841      IOEXCEPTION( TEXTFAIL, BAD_FORMAT_SPEC_CHAR );
1842
1843    case RepFact:
1844      if( isDEC(curr) )
1845      {
1846        dig = curr - '0';
1847        if( repetition > (ULONG_MAX - dig)/10 )
1848          IOEXCEPTION( TEXTFAIL, REPFAC_OVERFLOW );
1849        repetition = repetition*10 + dig;
1850        break;
1851      }
1852      goto test_for_control_codes;
1853
1854    case ConvClause:
1855      if( isDEC(curr) )
1856      {
1857        state = ClauseWidth;
1858        clausewidth = curr - '0';
1859        break;
1860      }
1861      if( curr == 'L' )
1862      {
1863        if( leftadjust )
1864          IOEXCEPTION( TEXTFAIL, DUPLICATE_QUALIFIER );
1865        leftadjust = True;
1866        break;
1867      }
1868      if( curr == 'E' )
1869      {
1870        if( overflowev )
1871          IOEXCEPTION( TEXTFAIL, DUPLICATE_QUALIFIER );
1872        overflowev = True;
1873        break;
1874      }
1875      if( curr == 'P' )
1876      {
1877        if( paddingdef )
1878          IOEXCEPTION( TEXTFAIL, DUPLICATE_QUALIFIER );
1879        paddingdef = True;
1880        state = CatchPadding;
1881        break;
1882      }
1883
1884test_for_variable_width: ;
1885      if( curr == 'V' )
1886      {
1887        dynamicwid = True;
1888        state = AfterWidth;
1889        break;
1890      }
1891      goto test_for_fraction_width;
1892
1893    case ClauseWidth:
1894      if( isDEC(curr) )
1895      {
1896        dig = curr - '0';
1897        if( clausewidth > (ULONG_MAX - dig)/10 )
1898          IOEXCEPTION( TEXTFAIL, CLAUSE_WIDTH_OVERFLOW );
1899        clausewidth = clausewidth*10 + dig;
1900        break;
1901      }
1902      /* fall through */
1903
1904test_for_fraction_width: ;
1905    case AfterWidth:
1906      if( curr == '.' )
1907      {
1908        if( convcode != DefaultConv && convcode != ScientConv )
1909          IOEXCEPTION( TEXTFAIL, NO_FRACTION );
1910        fractiondef = True;
1911        state = FractWidth;
1912        break;
1913      }
1914      goto test_for_exponent_width;
1915
1916    case FractWidth:
1917      if( isDEC( curr ) )
1918      {
1919        state = FractWidthCont;
1920        fractionwidth = curr - '0';
1921        break;
1922      }
1923      else
1924        IOEXCEPTION( TEXTFAIL, NO_FRACTION_WIDTH );
1925
1926    case FractWidthCont:
1927      if( isDEC( curr ) )
1928      {
1929        dig = curr - '0';
1930        if( fractionwidth > (ULONG_MAX - dig)/10 )
1931          IOEXCEPTION( TEXTFAIL, FRACTION_WIDTH_OVERFLOW );
1932        fractionwidth = fractionwidth*10 + dig;
1933        break;
1934      }
1935
1936test_for_exponent_width: ;
1937      if( curr == ':' )
1938      {
1939        if( convcode != ScientConv )
1940          IOEXCEPTION( TEXTFAIL, NO_EXPONENT );
1941        exponentdef = True;
1942        state = ExpoWidth;
1943        break;
1944      }
1945      goto test_for_final_percent;
1946
1947    case ExpoWidth:
1948      if( isDEC( curr ) )
1949      {
1950        state = ExpoWidthCont;
1951        exponentwidth = curr - '0';
1952        break;
1953      }
1954      else
1955        IOEXCEPTION( TEXTFAIL, NO_EXPONENT_WIDTH );
1956
1957    case ExpoWidthCont:
1958      if( isDEC( curr ) )
1959      {
1960        dig = curr - '0';
1961        if( exponentwidth > (ULONG_MAX - dig)/10 )
1962          IOEXCEPTION( TEXTFAIL, EXPONENT_WIDTH_OVERFLOW );
1963        exponentwidth = exponentwidth*10 + dig;
1964        break;
1965      }
1966      /* fall through  */
1967
1968test_for_final_percent: ;
1969    case ClauseEnd:
1970      if( curr == '%' )
1971      {
1972        state = LastPercent;
1973        break;
1974      }
1975
1976  do_the_action: ;
1977      actionptr[action]();
1978      state = FormatText;
1979      begtxt = fcs - 1;
1980      break;
1981
1982    case CatchPadding:
1983      paddingchar = curr;
1984      state = ConvClause;
1985      break;
1986
1987    case EditClause:
1988      if( isDEC(curr) )
1989      {
1990        state = ClauseWidth;
1991        clausewidth = curr - '0';
1992        break;
1993      }
1994      goto test_for_variable_width;
1995
1996    case LastPercent:
1997      actionptr[action]();
1998      if( curr == '.' )
1999      {
2000        state = FormatText;
2001        begtxt = fcs;
2002        break;
2003      }
2004      goto after_first_percent;
2005
2006    default:
2007      IOEXCEPTION( TEXTFAIL, INTERNAL_ERROR );
2008    }
2009  }
2010  switch( state )
2011  {
2012  case FormatText:
2013    ftextptr( begtxt, fcs );
2014    break;
2015  case FirstPercent:
2016  case LastPercent:
2017  case RepFact:
2018  case FractWidth:
2019  case ExpoWidth:
2020    IOEXCEPTION( TEXTFAIL, BAD_FORMAT_SPEC_CHAR );
2021  case CatchPadding:
2022    IOEXCEPTION( TEXTFAIL, NO_PAD_CHAR );
2023  default:
2024    actionptr[action]();
2025  }
2026
2027  *lenptr = len;
2028  *fcsptr = fcs;
2029  return NormalEnd;
2030}
2031
2032static
2033void
2034__read_format (char*           fmtptr,
2035               int             fmtlen,
2036               __tmp_IO_list*  ioptr,
2037               int             iolen,
2038               void*           inpptr,
2039               int             inplen )
2040{
2041  formatexit_t res;
2042  unsigned short l;
2043
2044  iostrptr = (char*)inpptr;
2045  iostrlen = inplen;
2046
2047  /* initialisation */
2048  iolist_index = 0;
2049  iolistptr    = ioptr;
2050  iolistlen    = iolen;
2051
2052  actionptr = readactions;
2053  ftextptr = scanstr;
2054
2055  if( (res = scanformcont( fmtptr, fmtlen, &fmtptr, &fmtlen )) == EndAtParen )
2056    IOEXCEPTION( TEXTFAIL, UNMATCHED_CLOSING_PAREN );
2057
2058  if( iolist_index != iolen )
2059    IOEXCEPTION( TEXTFAIL, EXCESS_IOLIST_ELEMENTS );
2060
2061  return;
2062}
2063
2064void
2065__readtext_f( Text_Mode*      the_text_loc,
2066              signed long     the_index,
2067              char*           fmtptr,
2068              int             fmtlen,
2069              __tmp_IO_list*  ioptr,
2070              int             iolen,
2071              char*           file,
2072              int             line )
2073{
2074  unsigned long info;
2075
2076  if( (info = setjmp( __io_exception )) )
2077    CHILLEXCEPTION( file, line, info>>16, info & 0xffff );
2078
2079  textptr       = the_text_loc;
2080  textrecptr    = textptr->text_record;
2081  actual_index  = textptr->actual_index;
2082  textindex     = the_index;
2083
2084  __read_format ( fmtptr, fmtlen, ioptr, iolen,
2085                  (char*)textrecptr + 2, textptr->text_record->len );
2086  textptr->actual_index = actual_index;
2087}
2088
2089void
2090__readtext_s( void*           string_ptr,
2091              int             string_len,
2092              char*           fmtptr,
2093              int             fmtlen,
2094              __tmp_IO_list*  ioptr,
2095              int             iolen,
2096              char*           file,
2097              int             line )
2098{
2099  int info;
2100
2101  if( (info = setjmp( __io_exception )) )
2102    CHILLEXCEPTION( file, line, info>>16, info & 0xffff );
2103
2104  textptr      = NULL;
2105  actual_index = 0;
2106
2107  __read_format ( fmtptr, fmtlen,  ioptr, iolen, string_ptr, string_len );
2108}
2109
2110static
2111void
2112__write_format (char*           fmtptr,
2113                int             fmtlen,
2114                __tmp_IO_list*  ioptr,
2115                int             iolen,
2116                void*           outptr,
2117                int             outlen )
2118{
2119  formatexit_t res;
2120  unsigned short l;
2121
2122  /* initialisation */
2123  maximum_index = actual_index;
2124  iolist_index = 0;
2125
2126  actionptr = writeactions;
2127  ftextptr  = emitstr;
2128  iolistptr = ioptr;
2129  iolistlen = iolen;
2130  iostrptr  = (char *)outptr + 2;
2131  iostrlen  = outlen;
2132
2133  if( (res = scanformcont( fmtptr, fmtlen, &fmtptr, &fmtlen )) == EndAtParen )
2134    IOEXCEPTION( TEXTFAIL, UNMATCHED_CLOSING_PAREN );
2135
2136  if( iolist_index != iolen )
2137    IOEXCEPTION( TEXTFAIL, EXCESS_IOLIST_ELEMENTS );
2138
2139  /* set length of output string */
2140#if _TEXTIO_DEBUG_
2141  printf( "maximum index = %d\n", maximum_index );
2142#endif
2143  l = maximum_index;
2144  MOV2(outptr,&l);
2145  return;
2146}
2147
2148void
2149__writetext_f( Text_Mode*      the_text_loc,
2150               signed long     the_index,
2151               char*           fmtptr,
2152               int             fmtlen,
2153               __tmp_IO_list*  ioptr,
2154               int             iolen,
2155               char*           file,
2156               int             line )
2157{
2158  int info;
2159
2160  if( (info = setjmp( __io_exception )) )
2161    CHILLEXCEPTION( file, line, info>>16, info & 0xffff );
2162
2163  textptr       = the_text_loc;
2164  textrecptr    = the_text_loc->text_record;
2165  textindex     = the_index;
2166  iolistptr     = ioptr;
2167  iolistlen     = iolen;
2168
2169  actual_index = textptr->actual_index;
2170  __write_format ( fmtptr, fmtlen, ioptr, iolen,
2171                   textrecptr, textptr->access_sub->reclength - 2 );
2172  textptr->actual_index = actual_index;
2173}
2174
2175void
2176__writetext_s( void*           string_ptr,
2177               int             string_len,
2178               char*           fmtptr,
2179               int             fmtlen,
2180               __tmp_IO_list*  ioptr,
2181               int             iolen,
2182               char*           file,
2183               int             line )
2184{
2185  int info;
2186
2187  if( (info = setjmp( __io_exception )) )
2188    CHILLEXCEPTION( file, line, info>>16, info & 0xffff );
2189
2190  textptr      = NULL;
2191  actual_index = 0;
2192
2193  __write_format ( fmtptr, fmtlen, ioptr, iolen, string_ptr, string_len );
2194}
2195