File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / trio.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:57 2012 UTC (12 years, 4 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, v2_7_8, HEAD
libxml2

    1: /*************************************************************************
    2:  *
    3:  * $Id: trio.c,v 1.1.1.1 2012/02/21 23:37:57 misho Exp $
    4:  *
    5:  * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
    6:  *
    7:  * Permission to use, copy, modify, and distribute this software for any
    8:  * purpose with or without fee is hereby granted, provided that the above
    9:  * copyright notice and this permission notice appear in all copies.
   10:  *
   11:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
   12:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
   13:  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
   14:  * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
   15:  *
   16:  *************************************************************************
   17:  *
   18:  * A note to trio contributors:
   19:  *
   20:  * Avoid heap allocation at all costs to ensure that the trio functions
   21:  * are async-safe. The exceptions are the printf/fprintf functions, which
   22:  * uses fputc, and the asprintf functions and the <alloc> modifier, which
   23:  * by design are required to allocate form the heap.
   24:  *
   25:  ************************************************************************/
   26: 
   27: /*
   28:  * TODO:
   29:  *  - Scan is probably too permissive about its modifiers.
   30:  *  - C escapes in %#[] ?
   31:  *  - Multibyte characters (done for format parsing, except scan groups)
   32:  *  - Complex numbers? (C99 _Complex)
   33:  *  - Boolean values? (C99 _Bool)
   34:  *  - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used
   35:  *    to print the mantissa, e.g. NaN(0xc000000000000000)
   36:  *  - Should we support the GNU %a alloc modifier? GNU has an ugly hack
   37:  *    for %a, because C99 used %a for other purposes. If specified as
   38:  *    %as or %a[ it is interpreted as the alloc modifier, otherwise as
   39:  *    the C99 hex-float. This means that you cannot scan %as as a hex-float
   40:  *    immediately followed by an 's'.
   41:  *  - Scanning of collating symbols.
   42:  */
   43: 
   44: /*************************************************************************
   45:  * Trio include files
   46:  */
   47: #include "triodef.h"
   48: #include "trio.h"
   49: #include "triop.h"
   50: #include "trionan.h"
   51: #if !defined(TRIO_MINIMAL)
   52: # include "triostr.h"
   53: #endif
   54: 
   55: /**************************************************************************
   56:  *
   57:  * Definitions
   58:  *
   59:  *************************************************************************/
   60: 
   61: #include <math.h>
   62: #include <limits.h>
   63: #include <float.h>
   64: 
   65: #if (defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) \
   66:      || defined(USE_MULTIBYTE) || TRIO_WIDECHAR) \
   67:     && !defined(_WIN32_WCE)
   68: # define TRIO_COMPILER_SUPPORTS_MULTIBYTE
   69: # if !defined(MB_LEN_MAX)
   70: #  define MB_LEN_MAX 6
   71: # endif
   72: #endif
   73: 
   74: #if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB)
   75: # define TRIO_COMPILER_SUPPORTS_MSVC_INT
   76: #endif
   77: 
   78: #if defined(_WIN32_WCE)
   79: #include <wincecompat.h>
   80: #endif
   81: 
   82: /*************************************************************************
   83:  * Generic definitions
   84:  */
   85: 
   86: #if !(defined(DEBUG) || defined(NDEBUG))
   87: # define NDEBUG
   88: #endif
   89: 
   90: #include <assert.h>
   91: #include <ctype.h>
   92: #if !defined(TRIO_COMPILER_SUPPORTS_C99)
   93: # define isblank(x) (((x)==32) || ((x)==9))
   94: #endif
   95: #if defined(TRIO_COMPILER_ANCIENT)
   96: # include <varargs.h>
   97: #else
   98: # include <stdarg.h>
   99: #endif
  100: #include <stddef.h>
  101: 
  102: #ifdef HAVE_ERRNO_H
  103: #include <errno.h>
  104: #endif
  105: 
  106: #ifndef NULL
  107: # define NULL 0
  108: #endif
  109: #define NIL ((char)0)
  110: #ifndef FALSE
  111: # define FALSE (1 == 0)
  112: # define TRUE (! FALSE)
  113: #endif
  114: #define BOOLEAN_T int
  115: 
  116: /* mincore() can be used for debugging purposes */
  117: #define VALID(x) (NULL != (x))
  118: 
  119: #if TRIO_ERRORS
  120:   /*
  121:    * Encode the error code and the position. This is decoded
  122:    * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
  123:    */
  124: # define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
  125: #else
  126: # define TRIO_ERROR_RETURN(x,y) (-1)
  127: #endif
  128: 
  129: typedef unsigned long trio_flags_t;
  130: 
  131: 
  132: /*************************************************************************
  133:  * Platform specific definitions
  134:  */
  135: #if defined(TRIO_PLATFORM_UNIX)
  136: # include <unistd.h>
  137: # include <signal.h>
  138: # include <locale.h>
  139: # define USE_LOCALE
  140: #endif /* TRIO_PLATFORM_UNIX */
  141: #if defined(TRIO_PLATFORM_VMS)
  142: # include <unistd.h>
  143: #endif
  144: #if defined(TRIO_PLATFORM_WIN32)
  145: # if defined(_WIN32_WCE)
  146: #  include <wincecompat.h>
  147: # else
  148: #  include <io.h>
  149: #  define read _read
  150: #  define write _write
  151: # endif
  152: #endif /* TRIO_PLATFORM_WIN32 */
  153: 
  154: #if TRIO_WIDECHAR
  155: # if defined(TRIO_COMPILER_SUPPORTS_ISO94)
  156: #  include <wchar.h>
  157: #  include <wctype.h>
  158: typedef wchar_t trio_wchar_t;
  159: typedef wint_t trio_wint_t;
  160: # else
  161: typedef char trio_wchar_t;
  162: typedef int trio_wint_t;
  163: #  define WCONST(x) L ## x
  164: #  define WEOF EOF
  165: #  define iswalnum(x) isalnum(x)
  166: #  define iswalpha(x) isalpha(x)
  167: #  define iswblank(x) isblank(x)
  168: #  define iswcntrl(x) iscntrl(x)
  169: #  define iswdigit(x) isdigit(x)
  170: #  define iswgraph(x) isgraph(x)
  171: #  define iswlower(x) islower(x)
  172: #  define iswprint(x) isprint(x)
  173: #  define iswpunct(x) ispunct(x)
  174: #  define iswspace(x) isspace(x)
  175: #  define iswupper(x) isupper(x)
  176: #  define iswxdigit(x) isxdigit(x)
  177: # endif
  178: #endif
  179: 
  180: 
  181: /*************************************************************************
  182:  * Compiler dependent definitions
  183:  */
  184: 
  185: /* Support for long long */
  186: #ifndef __cplusplus
  187: # if !defined(USE_LONGLONG)
  188: #  if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
  189: #   define USE_LONGLONG
  190: #  elif defined(TRIO_COMPILER_SUNPRO)
  191: #   define USE_LONGLONG
  192: #  elif defined(_LONG_LONG) || defined(_LONGLONG)
  193: #   define USE_LONGLONG
  194: #  endif
  195: # endif
  196: #endif
  197: 
  198: /* The extra long numbers */
  199: #if defined(USE_LONGLONG)
  200: typedef signed long long int trio_longlong_t;
  201: typedef unsigned long long int trio_ulonglong_t;
  202: #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
  203: typedef signed __int64 trio_longlong_t;
  204: typedef unsigned __int64 trio_ulonglong_t;
  205: #else
  206: typedef TRIO_SIGNED long int trio_longlong_t;
  207: typedef unsigned long int trio_ulonglong_t;
  208: #endif
  209: 
  210: /* Maximal and fixed integer types */
  211: #if defined(TRIO_COMPILER_SUPPORTS_C99)
  212: # include <stdint.h>
  213: typedef intmax_t trio_intmax_t;
  214: typedef uintmax_t trio_uintmax_t;
  215: typedef int8_t trio_int8_t;
  216: typedef int16_t trio_int16_t;
  217: typedef int32_t trio_int32_t;
  218: typedef int64_t trio_int64_t;
  219: #elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
  220: # include <inttypes.h>
  221: typedef intmax_t trio_intmax_t;
  222: typedef uintmax_t trio_uintmax_t;
  223: typedef int8_t trio_int8_t;
  224: typedef int16_t trio_int16_t;
  225: typedef int32_t trio_int32_t;
  226: typedef int64_t trio_int64_t;
  227: #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
  228: typedef trio_longlong_t trio_intmax_t;
  229: typedef trio_ulonglong_t trio_uintmax_t;
  230: typedef __int8 trio_int8_t;
  231: typedef __int16 trio_int16_t;
  232: typedef __int32 trio_int32_t;
  233: typedef __int64 trio_int64_t;
  234: #else
  235: typedef trio_longlong_t trio_intmax_t;
  236: typedef trio_ulonglong_t trio_uintmax_t;
  237: # if defined(TRIO_INT8_T)
  238: typedef TRIO_INT8_T trio_int8_t;
  239: # else
  240: typedef TRIO_SIGNED char trio_int8_t;
  241: # endif
  242: # if defined(TRIO_INT16_T)
  243: typedef TRIO_INT16_T trio_int16_t;
  244: # else
  245: typedef TRIO_SIGNED short trio_int16_t;
  246: # endif
  247: # if defined(TRIO_INT32_T)
  248: typedef TRIO_INT32_T trio_int32_t;
  249: # else
  250: typedef TRIO_SIGNED int trio_int32_t;
  251: # endif
  252: # if defined(TRIO_INT64_T)
  253: typedef TRIO_INT64_T trio_int64_t;
  254: # else
  255: typedef trio_longlong_t trio_int64_t;
  256: # endif
  257: #endif
  258: 
  259: #if (!(defined(TRIO_COMPILER_SUPPORTS_C99) \
  260:  || defined(TRIO_COMPILER_SUPPORTS_UNIX01))) \
  261:  && !defined(_WIN32_WCE)
  262: # define floorl(x) floor((double)(x))
  263: # define fmodl(x,y) fmod((double)(x),(double)(y))
  264: # define powl(x,y) pow((double)(x),(double)(y))
  265: #endif
  266: 
  267: #define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
  268: 
  269: /*************************************************************************
  270:  * Internal Definitions
  271:  */
  272: 
  273: #ifndef DECIMAL_DIG
  274: # define DECIMAL_DIG DBL_DIG
  275: #endif
  276: 
  277: /* Long double sizes */
  278: #ifdef LDBL_DIG
  279: # define MAX_MANTISSA_DIGITS LDBL_DIG
  280: # define MAX_EXPONENT_DIGITS 4
  281: # define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
  282: #else
  283: # define MAX_MANTISSA_DIGITS DECIMAL_DIG
  284: # define MAX_EXPONENT_DIGITS 3
  285: # define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
  286: #endif
  287: 
  288: #if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
  289: # undef LDBL_DIG
  290: # undef LDBL_MANT_DIG
  291: # undef LDBL_EPSILON
  292: # define LDBL_DIG DBL_DIG
  293: # define LDBL_MANT_DIG DBL_MANT_DIG
  294: # define LDBL_EPSILON DBL_EPSILON
  295: #endif
  296: 
  297: /* The maximal number of digits is for base 2 */
  298: #define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
  299: /* The width of a pointer. The number of bits in a hex digit is 4 */
  300: #define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
  301: 
  302: /* Infinite and Not-A-Number for floating-point */
  303: #define INFINITE_LOWER "inf"
  304: #define INFINITE_UPPER "INF"
  305: #define LONG_INFINITE_LOWER "infinite"
  306: #define LONG_INFINITE_UPPER "INFINITE"
  307: #define NAN_LOWER "nan"
  308: #define NAN_UPPER "NAN"
  309: 
  310: /* Various constants */
  311: enum {
  312:   TYPE_PRINT = 1,
  313:   TYPE_SCAN  = 2,
  314: 
  315:   /* Flags. FLAGS_LAST must be less than ULONG_MAX */
  316:   FLAGS_NEW                 = 0,
  317:   FLAGS_STICKY              = 1,
  318:   FLAGS_SPACE               = 2 * FLAGS_STICKY,
  319:   FLAGS_SHOWSIGN            = 2 * FLAGS_SPACE,
  320:   FLAGS_LEFTADJUST          = 2 * FLAGS_SHOWSIGN,
  321:   FLAGS_ALTERNATIVE         = 2 * FLAGS_LEFTADJUST,
  322:   FLAGS_SHORT               = 2 * FLAGS_ALTERNATIVE,
  323:   FLAGS_SHORTSHORT          = 2 * FLAGS_SHORT,
  324:   FLAGS_LONG                = 2 * FLAGS_SHORTSHORT,
  325:   FLAGS_QUAD                = 2 * FLAGS_LONG,
  326:   FLAGS_LONGDOUBLE          = 2 * FLAGS_QUAD,
  327:   FLAGS_SIZE_T              = 2 * FLAGS_LONGDOUBLE,
  328:   FLAGS_PTRDIFF_T           = 2 * FLAGS_SIZE_T,
  329:   FLAGS_INTMAX_T            = 2 * FLAGS_PTRDIFF_T,
  330:   FLAGS_NILPADDING          = 2 * FLAGS_INTMAX_T,
  331:   FLAGS_UNSIGNED            = 2 * FLAGS_NILPADDING,
  332:   FLAGS_UPPER               = 2 * FLAGS_UNSIGNED,
  333:   FLAGS_WIDTH               = 2 * FLAGS_UPPER,
  334:   FLAGS_WIDTH_PARAMETER     = 2 * FLAGS_WIDTH,
  335:   FLAGS_PRECISION           = 2 * FLAGS_WIDTH_PARAMETER,
  336:   FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
  337:   FLAGS_BASE                = 2 * FLAGS_PRECISION_PARAMETER,
  338:   FLAGS_BASE_PARAMETER      = 2 * FLAGS_BASE,
  339:   FLAGS_FLOAT_E             = 2 * FLAGS_BASE_PARAMETER,
  340:   FLAGS_FLOAT_G             = 2 * FLAGS_FLOAT_E,
  341:   FLAGS_QUOTE               = 2 * FLAGS_FLOAT_G,
  342:   FLAGS_WIDECHAR            = 2 * FLAGS_QUOTE,
  343:   FLAGS_ALLOC               = 2 * FLAGS_WIDECHAR,
  344:   FLAGS_IGNORE              = 2 * FLAGS_ALLOC,
  345:   FLAGS_IGNORE_PARAMETER    = 2 * FLAGS_IGNORE,
  346:   FLAGS_VARSIZE_PARAMETER   = 2 * FLAGS_IGNORE_PARAMETER,
  347:   FLAGS_FIXED_SIZE          = 2 * FLAGS_VARSIZE_PARAMETER,
  348:   FLAGS_LAST                = FLAGS_FIXED_SIZE,
  349:   /* Reused flags */
  350:   FLAGS_EXCLUDE             = FLAGS_SHORT,
  351:   FLAGS_USER_DEFINED        = FLAGS_IGNORE,
  352:   FLAGS_ROUNDING            = FLAGS_INTMAX_T,
  353:   /* Compounded flags */
  354:   FLAGS_ALL_VARSIZES        = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
  355:   FLAGS_ALL_SIZES           = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
  356: 
  357:   NO_POSITION  = -1,
  358:   NO_WIDTH     =  0,
  359:   NO_PRECISION = -1,
  360:   NO_SIZE      = -1,
  361: 
  362:   /* Do not change these */
  363:   NO_BASE      = -1,
  364:   MIN_BASE     =  2,
  365:   MAX_BASE     = 36,
  366:   BASE_BINARY  =  2,
  367:   BASE_OCTAL   =  8,
  368:   BASE_DECIMAL = 10,
  369:   BASE_HEX     = 16,
  370: 
  371:   /* Maximal number of allowed parameters */
  372:   MAX_PARAMETERS = 64,
  373:   /* Maximal number of characters in class */
  374:   MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
  375: 
  376:   /* Maximal string lengths for user-defined specifiers */
  377:   MAX_USER_NAME = 64,
  378:   MAX_USER_DATA = 256,
  379:   
  380:   /* Maximal length of locale separator strings */
  381:   MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
  382:   /* Maximal number of integers in grouping */
  383:   MAX_LOCALE_GROUPS = 64,
  384: 
  385:   /* Initial size of asprintf buffer */
  386:   DYNAMIC_START_SIZE = 32
  387: };
  388: 
  389: #define NO_GROUPING ((int)CHAR_MAX)
  390: 
  391: /* Fundamental formatting parameter types */
  392: #define FORMAT_UNKNOWN   0
  393: #define FORMAT_INT       1
  394: #define FORMAT_DOUBLE    2
  395: #define FORMAT_CHAR      3
  396: #define FORMAT_STRING    4
  397: #define FORMAT_POINTER   5
  398: #define FORMAT_COUNT     6
  399: #define FORMAT_PARAMETER 7
  400: #define FORMAT_GROUP     8
  401: #if TRIO_GNU
  402: # define FORMAT_ERRNO    9
  403: #endif
  404: #if TRIO_EXTENSION
  405: # define FORMAT_USER_DEFINED 10
  406: #endif
  407: 
  408: /* Character constants */
  409: #define CHAR_IDENTIFIER '%'
  410: #define CHAR_BACKSLASH '\\'
  411: #define CHAR_QUOTE '\"'
  412: #define CHAR_ADJUST ' '
  413: 
  414: /* Character class expressions */
  415: #define CLASS_ALNUM "[:alnum:]"
  416: #define CLASS_ALPHA "[:alpha:]"
  417: #define CLASS_BLANK "[:blank:]"
  418: #define CLASS_CNTRL "[:cntrl:]"
  419: #define CLASS_DIGIT "[:digit:]"
  420: #define CLASS_GRAPH "[:graph:]"
  421: #define CLASS_LOWER "[:lower:]"
  422: #define CLASS_PRINT "[:print:]"
  423: #define CLASS_PUNCT "[:punct:]"
  424: #define CLASS_SPACE "[:space:]"
  425: #define CLASS_UPPER "[:upper:]"
  426: #define CLASS_XDIGIT "[:xdigit:]"
  427: 
  428: /*
  429:  * SPECIFIERS:
  430:  *
  431:  *
  432:  * a  Hex-float
  433:  * A  Hex-float
  434:  * c  Character
  435:  * C  Widechar character (wint_t)
  436:  * d  Decimal
  437:  * e  Float
  438:  * E  Float
  439:  * F  Float
  440:  * F  Float
  441:  * g  Float
  442:  * G  Float
  443:  * i  Integer
  444:  * m  Error message
  445:  * n  Count
  446:  * o  Octal
  447:  * p  Pointer
  448:  * s  String
  449:  * S  Widechar string (wchar_t *)
  450:  * u  Unsigned
  451:  * x  Hex
  452:  * X  Hex
  453:  * [] Group
  454:  * <> User-defined
  455:  *
  456:  * Reserved:
  457:  *
  458:  * D  Binary Coded Decimal %D(length,precision) (OS/390)
  459:  */
  460: #define SPECIFIER_CHAR 'c'
  461: #define SPECIFIER_STRING 's'
  462: #define SPECIFIER_DECIMAL 'd'
  463: #define SPECIFIER_INTEGER 'i'
  464: #define SPECIFIER_UNSIGNED 'u'
  465: #define SPECIFIER_OCTAL 'o'
  466: #define SPECIFIER_HEX 'x'
  467: #define SPECIFIER_HEX_UPPER 'X'
  468: #define SPECIFIER_FLOAT_E 'e'
  469: #define SPECIFIER_FLOAT_E_UPPER 'E'
  470: #define SPECIFIER_FLOAT_F 'f'
  471: #define SPECIFIER_FLOAT_F_UPPER 'F'
  472: #define SPECIFIER_FLOAT_G 'g'
  473: #define SPECIFIER_FLOAT_G_UPPER 'G'
  474: #define SPECIFIER_POINTER 'p'
  475: #define SPECIFIER_GROUP '['
  476: #define SPECIFIER_UNGROUP ']'
  477: #define SPECIFIER_COUNT 'n'
  478: #if TRIO_UNIX98
  479: # define SPECIFIER_CHAR_UPPER 'C'
  480: # define SPECIFIER_STRING_UPPER 'S'
  481: #endif
  482: #if TRIO_C99
  483: # define SPECIFIER_HEXFLOAT 'a'
  484: # define SPECIFIER_HEXFLOAT_UPPER 'A'
  485: #endif
  486: #if TRIO_GNU
  487: # define SPECIFIER_ERRNO 'm'
  488: #endif
  489: #if TRIO_EXTENSION
  490: # define SPECIFIER_BINARY 'b'
  491: # define SPECIFIER_BINARY_UPPER 'B'
  492: # define SPECIFIER_USER_DEFINED_BEGIN '<'
  493: # define SPECIFIER_USER_DEFINED_END '>'
  494: # define SPECIFIER_USER_DEFINED_SEPARATOR ':'
  495: #endif
  496: 
  497: /*
  498:  * QUALIFIERS:
  499:  *
  500:  *
  501:  * Numbers = d,i,o,u,x,X
  502:  * Float = a,A,e,E,f,F,g,G
  503:  * String = s
  504:  * Char = c
  505:  *
  506:  *
  507:  * 9$ Position
  508:  *      Use the 9th parameter. 9 can be any number between 1 and
  509:  *      the maximal argument
  510:  *
  511:  * 9 Width
  512:  *      Set width to 9. 9 can be any number, but must not be postfixed
  513:  *      by '$'
  514:  *
  515:  * h  Short
  516:  *    Numbers:
  517:  *      (unsigned) short int
  518:  *
  519:  * hh Short short
  520:  *    Numbers:
  521:  *      (unsigned) char
  522:  *
  523:  * l  Long
  524:  *    Numbers:
  525:  *      (unsigned) long int
  526:  *    String:
  527:  *      as the S specifier
  528:  *    Char:
  529:  *      as the C specifier
  530:  *
  531:  * ll Long Long
  532:  *    Numbers:
  533:  *      (unsigned) long long int
  534:  *
  535:  * L  Long Double
  536:  *    Float
  537:  *      long double
  538:  *
  539:  * #  Alternative
  540:  *    Float:
  541:  *      Decimal-point is always present
  542:  *    String:
  543:  *      non-printable characters are handled as \number
  544:  *
  545:  *    Spacing
  546:  *
  547:  * +  Sign
  548:  *
  549:  * -  Alignment
  550:  *
  551:  * .  Precision
  552:  *
  553:  * *  Parameter
  554:  *    print: use parameter
  555:  *    scan: no parameter (ignore)
  556:  *
  557:  * q  Quad
  558:  *
  559:  * Z  size_t
  560:  *
  561:  * w  Widechar
  562:  *
  563:  * '  Thousands/quote
  564:  *    Numbers:
  565:  *      Integer part grouped in thousands
  566:  *    Binary numbers:
  567:  *      Number grouped in nibbles (4 bits)
  568:  *    String:
  569:  *      Quoted string
  570:  *
  571:  * j  intmax_t
  572:  * t  prtdiff_t
  573:  * z  size_t
  574:  *
  575:  * !  Sticky
  576:  * @  Parameter (for both print and scan)
  577:  *
  578:  * I  n-bit Integer
  579:  *    Numbers:
  580:  *      The following options exists
  581:  *        I8  = 8-bit integer
  582:  *        I16 = 16-bit integer
  583:  *        I32 = 32-bit integer
  584:  *        I64 = 64-bit integer
  585:  */
  586: #define QUALIFIER_POSITION '$'
  587: #define QUALIFIER_SHORT 'h'
  588: #define QUALIFIER_LONG 'l'
  589: #define QUALIFIER_LONG_UPPER 'L'
  590: #define QUALIFIER_ALTERNATIVE '#'
  591: #define QUALIFIER_SPACE ' '
  592: #define QUALIFIER_PLUS '+'
  593: #define QUALIFIER_MINUS '-'
  594: #define QUALIFIER_DOT '.'
  595: #define QUALIFIER_STAR '*'
  596: #define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
  597: #if TRIO_C99
  598: # define QUALIFIER_SIZE_T 'z'
  599: # define QUALIFIER_PTRDIFF_T 't'
  600: # define QUALIFIER_INTMAX_T 'j'
  601: #endif
  602: #if TRIO_BSD || TRIO_GNU
  603: # define QUALIFIER_QUAD 'q'
  604: #endif
  605: #if TRIO_GNU
  606: # define QUALIFIER_SIZE_T_UPPER 'Z'
  607: #endif
  608: #if TRIO_MISC
  609: # define QUALIFIER_WIDECHAR 'w'
  610: #endif
  611: #if TRIO_MICROSOFT
  612: # define QUALIFIER_FIXED_SIZE 'I'
  613: #endif
  614: #if TRIO_EXTENSION
  615: # define QUALIFIER_QUOTE '\''
  616: # define QUALIFIER_STICKY '!'
  617: # define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
  618: # define QUALIFIER_PARAM '@' /* Experimental */
  619: # define QUALIFIER_COLON ':' /* For scanlists */
  620: # define QUALIFIER_EQUAL '=' /* For scanlists */
  621: # define QUALIFIER_ROUNDING_UPPER 'R'
  622: #endif
  623: 
  624: 
  625: /*************************************************************************
  626:  *
  627:  * Internal Structures
  628:  *
  629:  *************************************************************************/
  630: 
  631: /* Parameters */
  632: typedef struct {
  633:   /* An indication of which entry in the data union is used */
  634:   int type;
  635:   /* The flags */
  636:   trio_flags_t flags;
  637:   /* The width qualifier */
  638:   int width;
  639:   /* The precision qualifier */
  640:   int precision;
  641:   /* The base qualifier */
  642:   int base;
  643:   /* The size for the variable size qualifier */
  644:   int varsize;
  645:   /* The marker of the end of the specifier */
  646:   int indexAfterSpecifier;
  647:   /* The data from the argument list */
  648:   union {
  649:     char *string;
  650: #if TRIO_WIDECHAR
  651:     trio_wchar_t *wstring;
  652: #endif
  653:     trio_pointer_t pointer;
  654:     union {
  655:       trio_intmax_t as_signed;
  656:       trio_uintmax_t as_unsigned;
  657:     } number;
  658:     double doubleNumber;
  659:     double *doublePointer;
  660:     trio_long_double_t longdoubleNumber;
  661:     trio_long_double_t *longdoublePointer;
  662:     int errorNumber;
  663:   } data;
  664:   /* For the user-defined specifier */
  665:   char user_name[MAX_USER_NAME];
  666:   char user_data[MAX_USER_DATA];
  667: } trio_parameter_t;
  668: 
  669: /* Container for customized functions */
  670: typedef struct {
  671:   union {
  672:     trio_outstream_t out;
  673:     trio_instream_t in;
  674:   } stream;
  675:   trio_pointer_t closure;
  676: } trio_custom_t;
  677: 
  678: /* General trio "class" */
  679: typedef struct _trio_class_t {
  680:   /*
  681:    * The function to write characters to a stream.
  682:    */
  683:   void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
  684:   /*
  685:    * The function to read characters from a stream.
  686:    */
  687:   void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
  688:   /*
  689:    * The current location in the stream.
  690:    */
  691:   trio_pointer_t location;
  692:   /*
  693:    * The character currently being processed.
  694:    */
  695:   int current;
  696:   /*
  697:    * The number of characters that would have been written/read
  698:    * if there had been sufficient space.
  699:    */
  700:   int processed;
  701:   /*
  702:    * The number of characters that are actually written/read.
  703:    * Processed and committed will only differ for the *nprintf
  704:    * and *nscanf functions.
  705:    */
  706:   int committed;
  707:   /*
  708:    * The upper limit of characters that may be written/read.
  709:    */
  710:   int max;
  711:   /*
  712:    * The last output error that was detected.
  713:    */
  714:   int error;
  715: } trio_class_t;
  716: 
  717: /* References (for user-defined callbacks) */
  718: typedef struct _trio_reference_t {
  719:   trio_class_t *data;
  720:   trio_parameter_t *parameter;
  721: } trio_reference_t;
  722: 
  723: /* Registered entries (for user-defined callbacks) */
  724: typedef struct _trio_userdef_t {
  725:   struct _trio_userdef_t *next;
  726:   trio_callback_t callback;
  727:   char *name;
  728: } trio_userdef_t;
  729: 
  730: /*************************************************************************
  731:  *
  732:  * Internal Variables
  733:  *
  734:  *************************************************************************/
  735: 
  736: static TRIO_CONST char rcsid[] = "@(#)$Id: trio.c,v 1.1.1.1 2012/02/21 23:37:57 misho Exp $";
  737: 
  738: /*
  739:  * Need this to workaround a parser bug in HP C/iX compiler that fails
  740:  * to resolves macro definitions that includes type 'long double',
  741:  * e.g: va_arg(arg_ptr, long double)
  742:  */
  743: #if defined(TRIO_PLATFORM_MPEIX)
  744: static TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
  745: #endif
  746: 
  747: static TRIO_CONST char internalNullString[] = "(nil)";
  748: 
  749: #if defined(USE_LOCALE)
  750: static struct lconv *internalLocaleValues = NULL;
  751: #endif
  752: 
  753: /*
  754:  * UNIX98 says "in a locale where the radix character is not defined,
  755:  * the radix character defaults to a period (.)"
  756:  */
  757: static int internalDecimalPointLength = 1;
  758: static int internalThousandSeparatorLength = 1;
  759: static char internalDecimalPoint = '.';
  760: static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
  761: static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
  762: static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
  763: 
  764: static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  765: static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  766: static BOOLEAN_T internalDigitsUnconverted = TRUE;
  767: static int internalDigitArray[128];
  768: #if TRIO_EXTENSION
  769: static BOOLEAN_T internalCollationUnconverted = TRUE;
  770: static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
  771: #endif
  772: 
  773: #if TRIO_EXTENSION
  774: static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
  775: static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
  776: static trio_userdef_t *internalUserDef = NULL;
  777: #endif
  778: 
  779: 
  780: /*************************************************************************
  781:  *
  782:  * Internal Functions
  783:  *
  784:  ************************************************************************/
  785: 
  786: #if defined(TRIO_MINIMAL)
  787: # define TRIO_STRING_PUBLIC static
  788: # include "triostr.c"
  789: #endif /* defined(TRIO_MINIMAL) */
  790: 
  791: /*************************************************************************
  792:  * TrioIsQualifier
  793:  *
  794:  * Description:
  795:  *  Remember to add all new qualifiers to this function.
  796:  *  QUALIFIER_POSITION must not be added.
  797:  */
  798: TRIO_PRIVATE BOOLEAN_T
  799: TrioIsQualifier
  800: TRIO_ARGS1((character),
  801: 	   TRIO_CONST char character)
  802: {
  803:   /* QUALIFIER_POSITION is not included */
  804:   switch (character)
  805:     {
  806:     case '0': case '1': case '2': case '3': case '4':
  807:     case '5': case '6': case '7': case '8': case '9':
  808:     case QUALIFIER_PLUS:
  809:     case QUALIFIER_MINUS:
  810:     case QUALIFIER_SPACE:
  811:     case QUALIFIER_DOT:
  812:     case QUALIFIER_STAR:
  813:     case QUALIFIER_ALTERNATIVE:
  814:     case QUALIFIER_SHORT:
  815:     case QUALIFIER_LONG:
  816:     case QUALIFIER_LONG_UPPER:
  817:     case QUALIFIER_CIRCUMFLEX:
  818: #if defined(QUALIFIER_SIZE_T)
  819:     case QUALIFIER_SIZE_T:
  820: #endif
  821: #if defined(QUALIFIER_PTRDIFF_T)
  822:     case QUALIFIER_PTRDIFF_T:
  823: #endif
  824: #if defined(QUALIFIER_INTMAX_T)
  825:     case QUALIFIER_INTMAX_T:
  826: #endif
  827: #if defined(QUALIFIER_QUAD)
  828:     case QUALIFIER_QUAD:
  829: #endif
  830: #if defined(QUALIFIER_SIZE_T_UPPER)
  831:     case QUALIFIER_SIZE_T_UPPER:
  832: #endif
  833: #if defined(QUALIFIER_WIDECHAR)
  834:     case QUALIFIER_WIDECHAR:
  835: #endif
  836: #if defined(QUALIFIER_QUOTE)
  837:     case QUALIFIER_QUOTE:
  838: #endif
  839: #if defined(QUALIFIER_STICKY)
  840:     case QUALIFIER_STICKY:
  841: #endif
  842: #if defined(QUALIFIER_VARSIZE)
  843:     case QUALIFIER_VARSIZE:
  844: #endif
  845: #if defined(QUALIFIER_PARAM)
  846:     case QUALIFIER_PARAM:
  847: #endif
  848: #if defined(QUALIFIER_FIXED_SIZE)
  849:     case QUALIFIER_FIXED_SIZE:
  850: #endif
  851: #if defined(QUALIFIER_ROUNDING_UPPER)
  852:     case QUALIFIER_ROUNDING_UPPER:
  853: #endif
  854:       return TRUE;
  855:     default:
  856:       return FALSE;
  857:     }
  858: }
  859: 
  860: /*************************************************************************
  861:  * TrioSetLocale
  862:  */
  863: #if defined(USE_LOCALE)
  864: TRIO_PRIVATE void
  865: TrioSetLocale(TRIO_NOARGS)
  866: {
  867:   internalLocaleValues = (struct lconv *)localeconv();
  868:   if (internalLocaleValues)
  869:     {
  870:       if ((internalLocaleValues->decimal_point) &&
  871: 	  (internalLocaleValues->decimal_point[0] != NIL))
  872: 	{
  873: 	  internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
  874: 	  if (internalDecimalPointLength == 1)
  875: 	    {
  876: 	      internalDecimalPoint = internalLocaleValues->decimal_point[0];
  877: 	    }
  878: 	  else
  879: 	    {
  880: 	      internalDecimalPoint = NIL;
  881: 	      trio_copy_max(internalDecimalPointString,
  882: 			    sizeof(internalDecimalPointString),
  883: 			    internalLocaleValues->decimal_point);
  884: 	    }
  885: 	}
  886:       if ((internalLocaleValues->thousands_sep) &&
  887: 	  (internalLocaleValues->thousands_sep[0] != NIL))
  888: 	{
  889: 	  trio_copy_max(internalThousandSeparator,
  890: 			sizeof(internalThousandSeparator),
  891: 			internalLocaleValues->thousands_sep);
  892: 	  internalThousandSeparatorLength = trio_length(internalThousandSeparator);
  893: 	}
  894:       if ((internalLocaleValues->grouping) &&
  895: 	  (internalLocaleValues->grouping[0] != NIL))
  896: 	{
  897: 	  trio_copy_max(internalGrouping,
  898: 			sizeof(internalGrouping),
  899: 			internalLocaleValues->grouping);
  900: 	}
  901:     }
  902: }
  903: #endif /* defined(USE_LOCALE) */
  904: 
  905: TRIO_PRIVATE int
  906: TrioCalcThousandSeparatorLength
  907: TRIO_ARGS1((digits),
  908: 	   int digits)
  909: {
  910: #if TRIO_EXTENSION
  911:   int count = 0;
  912:   int step = NO_GROUPING;
  913:   char *groupingPointer = internalGrouping;
  914: 
  915:   while (digits > 0)
  916:     {
  917:       if (*groupingPointer == CHAR_MAX)
  918: 	{
  919: 	  /* Disable grouping */
  920: 	  break; /* while */
  921: 	}
  922:       else if (*groupingPointer == 0)
  923: 	{
  924: 	  /* Repeat last group */
  925: 	  if (step == NO_GROUPING)
  926: 	    {
  927: 	      /* Error in locale */
  928: 	      break; /* while */
  929: 	    }
  930: 	}
  931:       else
  932: 	{
  933: 	  step = *groupingPointer++;
  934: 	}
  935:       if (digits > step)
  936: 	count += internalThousandSeparatorLength;
  937:       digits -= step;
  938:     }
  939:   return count;
  940: #else
  941:   return 0;
  942: #endif
  943: }
  944: 
  945: TRIO_PRIVATE BOOLEAN_T
  946: TrioFollowedBySeparator
  947: TRIO_ARGS1((position),
  948: 	   int position)
  949: {
  950: #if TRIO_EXTENSION
  951:   int step = 0;
  952:   char *groupingPointer = internalGrouping;
  953: 
  954:   position--;
  955:   if (position == 0)
  956:     return FALSE;
  957:   while (position > 0)
  958:     {
  959:       if (*groupingPointer == CHAR_MAX)
  960: 	{
  961: 	  /* Disable grouping */
  962: 	  break; /* while */
  963: 	}
  964:       else if (*groupingPointer != 0)
  965: 	{
  966: 	  step = *groupingPointer++;
  967: 	}
  968:       if (step == 0)
  969: 	break;
  970:       position -= step;
  971:     }
  972:   return (position == 0);
  973: #else
  974:   return FALSE;
  975: #endif
  976: }
  977: 
  978: /*************************************************************************
  979:  * TrioGetPosition
  980:  *
  981:  * Get the %n$ position.
  982:  */
  983: TRIO_PRIVATE int
  984: TrioGetPosition
  985: TRIO_ARGS2((format, indexPointer),
  986: 	   TRIO_CONST char *format,
  987: 	   int *indexPointer)
  988: {
  989: #if TRIO_UNIX98
  990:   char *tmpformat;
  991:   int number = 0;
  992:   int index = *indexPointer;
  993: 
  994:   number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
  995:   index = (int)(tmpformat - format);
  996:   if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
  997:     {
  998:       *indexPointer = index;
  999:       /*
 1000:        * number is decreased by 1, because n$ starts from 1, whereas
 1001:        * the array it is indexing starts from 0.
 1002:        */
 1003:       return number - 1;
 1004:     }
 1005: #endif
 1006:   return NO_POSITION;
 1007: }
 1008: 
 1009: #if TRIO_EXTENSION
 1010: /*************************************************************************
 1011:  * TrioFindNamespace
 1012:  *
 1013:  * Find registered user-defined specifier.
 1014:  * The prev argument is used for optimization only.
 1015:  */
 1016: TRIO_PRIVATE trio_userdef_t *
 1017: TrioFindNamespace
 1018: TRIO_ARGS2((name, prev),
 1019: 	   TRIO_CONST char *name,
 1020: 	   trio_userdef_t **prev)
 1021: {
 1022:   trio_userdef_t *def;
 1023:   
 1024:   if (internalEnterCriticalRegion)
 1025:     (void)internalEnterCriticalRegion(NULL);
 1026:   
 1027:   for (def = internalUserDef; def; def = def->next)
 1028:     {
 1029:       /* Case-sensitive string comparison */
 1030:       if (trio_equal_case(def->name, name))
 1031: 	break;
 1032:       
 1033:       if (prev)
 1034: 	*prev = def;
 1035:     }
 1036:   
 1037:   if (internalLeaveCriticalRegion)
 1038:     (void)internalLeaveCriticalRegion(NULL);
 1039:   
 1040:   return def;
 1041: }
 1042: #endif
 1043: 
 1044: /*************************************************************************
 1045:  * TrioPower
 1046:  *
 1047:  * Description:
 1048:  *  Calculate pow(base, exponent), where number and exponent are integers.
 1049:  */
 1050: TRIO_PRIVATE trio_long_double_t
 1051: TrioPower
 1052: TRIO_ARGS2((number, exponent),
 1053: 	   int number,
 1054: 	   int exponent)
 1055: {
 1056:   trio_long_double_t result;
 1057: 
 1058:   if (number == 10)
 1059:     {
 1060:       switch (exponent)
 1061: 	{
 1062: 	  /* Speed up calculation of common cases */
 1063: 	case 0:
 1064: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
 1065: 	  break;
 1066: 	case 1:
 1067: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
 1068: 	  break;
 1069: 	case 2:
 1070: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
 1071: 	  break;
 1072: 	case 3:
 1073: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
 1074: 	  break;
 1075: 	case 4:
 1076: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
 1077: 	  break;
 1078: 	case 5:
 1079: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
 1080: 	  break;
 1081: 	case 6:
 1082: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
 1083: 	  break;
 1084: 	case 7:
 1085: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
 1086: 	  break;
 1087: 	case 8:
 1088: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
 1089: 	  break;
 1090: 	case 9:
 1091: 	  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
 1092: 	  break;
 1093: 	default:
 1094: 	  result = powl((trio_long_double_t)number,
 1095: 			(trio_long_double_t)exponent);
 1096: 	  break;
 1097: 	}
 1098:     }
 1099:   else
 1100:     {
 1101:       return powl((trio_long_double_t)number, (trio_long_double_t)exponent);
 1102:     }
 1103:   return result;
 1104: }
 1105: 
 1106: /*************************************************************************
 1107:  * TrioLogarithm
 1108:  */
 1109: TRIO_PRIVATE double
 1110: TrioLogarithm
 1111: TRIO_ARGS2((number, base),
 1112: 	   double number,
 1113: 	   int base)
 1114: {
 1115:   double result;
 1116: 
 1117:   if (number <= 0.0)
 1118:     {
 1119:       /* xlC crashes on log(0) */
 1120:       result = (number == 0.0) ? trio_ninf() : trio_nan();
 1121:     }
 1122:   else
 1123:     {
 1124:       if (base == 10)
 1125: 	{
 1126: 	  result = log10(number);
 1127: 	}
 1128:       else
 1129: 	{
 1130: 	  result = log10(number) / log10((double)base);
 1131: 	}
 1132:     }
 1133:   return result;
 1134: }
 1135: 
 1136: /*************************************************************************
 1137:  * TrioLogarithmBase
 1138:  */
 1139: TRIO_PRIVATE double
 1140: TrioLogarithmBase
 1141: TRIO_ARGS1((base),
 1142: 	   int base)
 1143: {
 1144:   switch (base)
 1145:     {
 1146:     case BASE_BINARY : return 1.0;
 1147:     case BASE_OCTAL  : return 3.0;
 1148:     case BASE_DECIMAL: return 3.321928094887362345;
 1149:     case BASE_HEX    : return 4.0;
 1150:     default          : return TrioLogarithm((double)base, 2);
 1151:     }
 1152: }
 1153: 
 1154: /*************************************************************************
 1155:  * TrioParse
 1156:  *
 1157:  * Description:
 1158:  *  Parse the format string
 1159:  */
 1160: TRIO_PRIVATE int
 1161: TrioParse
 1162: TRIO_ARGS5((type, format, parameters, arglist, argarray),
 1163: 	   int type,
 1164: 	   TRIO_CONST char *format,
 1165: 	   trio_parameter_t *parameters,
 1166: 	   va_list *arglist,
 1167: 	   trio_pointer_t *argarray)
 1168: {
 1169:   /* Count the number of times a parameter is referenced */
 1170:   unsigned short usedEntries[MAX_PARAMETERS];
 1171:   /* Parameter counters */
 1172:   int parameterPosition;
 1173:   int currentParam;
 1174:   int maxParam = -1;
 1175:   /* Utility variables */
 1176:   trio_flags_t flags;
 1177:   int width;
 1178:   int precision;
 1179:   int varsize;
 1180:   int base;
 1181:   int index;  /* Index into formatting string */
 1182:   int dots;  /* Count number of dots in modifier part */
 1183:   BOOLEAN_T positional;  /* Does the specifier have a positional? */
 1184:   BOOLEAN_T gotSticky = FALSE;  /* Are there any sticky modifiers at all? */
 1185:   /*
 1186:    * indices specifies the order in which the parameters must be
 1187:    * read from the va_args (this is necessary to handle positionals)
 1188:    */
 1189:   int indices[MAX_PARAMETERS];
 1190:   int pos = 0;
 1191:   /* Various variables */
 1192:   char ch;
 1193: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 1194:   int charlen;
 1195: #endif
 1196:   int save_errno;
 1197:   int i = -1;
 1198:   int num;
 1199:   char *tmpformat;
 1200: 
 1201:   /* One and only one of arglist and argarray must be used */
 1202:   assert((arglist != NULL) ^ (argarray != NULL));
 1203:   
 1204:   /*
 1205:    * The 'parameters' array is not initialized, but we need to
 1206:    * know which entries we have used.
 1207:    */
 1208:   memset(usedEntries, 0, sizeof(usedEntries));
 1209: 
 1210:   save_errno = errno;
 1211:   index = 0;
 1212:   parameterPosition = 0;
 1213: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 1214:   (void)mblen(NULL, 0);
 1215: #endif
 1216:   
 1217:   while (format[index])
 1218:     {
 1219: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 1220:       if (! isascii(format[index]))
 1221: 	{
 1222: 	  /*
 1223: 	   * Multibyte characters cannot be legal specifiers or
 1224: 	   * modifiers, so we skip over them.
 1225: 	   */
 1226: 	  charlen = mblen(&format[index], MB_LEN_MAX);
 1227: 	  index += (charlen > 0) ? charlen : 1;
 1228: 	  continue; /* while */
 1229: 	}
 1230: #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
 1231:       if (CHAR_IDENTIFIER == format[index++])
 1232: 	{
 1233: 	  if (CHAR_IDENTIFIER == format[index])
 1234: 	    {
 1235: 	      index++;
 1236: 	      continue; /* while */
 1237: 	    }
 1238: 
 1239: 	  flags = FLAGS_NEW;
 1240: 	  dots = 0;
 1241: 	  currentParam = TrioGetPosition(format, &index);
 1242: 	  positional = (NO_POSITION != currentParam);
 1243: 	  if (!positional)
 1244: 	    {
 1245: 	      /* We have no positional, get the next counter */
 1246: 	      currentParam = parameterPosition;
 1247: 	    }
 1248:           if(currentParam >= MAX_PARAMETERS)
 1249: 	    {
 1250: 	      /* Bail out completely to make the error more obvious */
 1251: 	      return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
 1252: 	    }
 1253: 
 1254: 	  if (currentParam > maxParam)
 1255: 	    maxParam = currentParam;
 1256: 
 1257: 	  /* Default values */
 1258: 	  width = NO_WIDTH;
 1259: 	  precision = NO_PRECISION;
 1260: 	  base = NO_BASE;
 1261: 	  varsize = NO_SIZE;
 1262: 
 1263: 	  while (TrioIsQualifier(format[index]))
 1264: 	    {
 1265: 	      ch = format[index++];
 1266: 
 1267: 	      switch (ch)
 1268: 		{
 1269: 		case QUALIFIER_SPACE:
 1270: 		  flags |= FLAGS_SPACE;
 1271: 		  break;
 1272: 
 1273: 		case QUALIFIER_PLUS:
 1274: 		  flags |= FLAGS_SHOWSIGN;
 1275: 		  break;
 1276: 
 1277: 		case QUALIFIER_MINUS:
 1278: 		  flags |= FLAGS_LEFTADJUST;
 1279: 		  flags &= ~FLAGS_NILPADDING;
 1280: 		  break;
 1281: 
 1282: 		case QUALIFIER_ALTERNATIVE:
 1283: 		  flags |= FLAGS_ALTERNATIVE;
 1284: 		  break;
 1285: 
 1286: 		case QUALIFIER_DOT:
 1287: 		  if (dots == 0) /* Precision */
 1288: 		    {
 1289: 		      dots++;
 1290: 
 1291: 		      /* Skip if no precision */
 1292: 		      if (QUALIFIER_DOT == format[index])
 1293: 			break;
 1294: 		      
 1295: 		      /* After the first dot we have the precision */
 1296: 		      flags |= FLAGS_PRECISION;
 1297: 		      if ((QUALIFIER_STAR == format[index])
 1298: #if defined(QUALIFIER_PARAM)
 1299: 			  || (QUALIFIER_PARAM == format[index])
 1300: #endif
 1301: 			  )
 1302: 			{
 1303: 			  index++;
 1304: 			  flags |= FLAGS_PRECISION_PARAMETER;
 1305: 
 1306: 			  precision = TrioGetPosition(format, &index);
 1307: 			  if (precision == NO_POSITION)
 1308: 			    {
 1309: 			      parameterPosition++;
 1310: 			      if (positional)
 1311: 				precision = parameterPosition;
 1312: 			      else
 1313: 				{
 1314: 				  precision = currentParam;
 1315: 				  currentParam = precision + 1;
 1316: 				}
 1317: 			    }
 1318: 			  else
 1319: 			    {
 1320: 			      if (! positional)
 1321: 				currentParam = precision + 1;
 1322: 			      if (width > maxParam)
 1323: 				maxParam = precision;
 1324: 			    }
 1325: 			  if (currentParam > maxParam)
 1326: 			    maxParam = currentParam;
 1327: 			}
 1328: 		      else
 1329: 			{
 1330: 			  precision = trio_to_long(&format[index],
 1331: 						   &tmpformat,
 1332: 						   BASE_DECIMAL);
 1333: 			  index = (int)(tmpformat - format);
 1334: 			}
 1335: 		    }
 1336: 		  else if (dots == 1) /* Base */
 1337: 		    {
 1338: 		      dots++;
 1339: 		      
 1340: 		      /* After the second dot we have the base */
 1341: 		      flags |= FLAGS_BASE;
 1342: 		      if ((QUALIFIER_STAR == format[index])
 1343: #if defined(QUALIFIER_PARAM)
 1344: 			  || (QUALIFIER_PARAM == format[index])
 1345: #endif
 1346: 			  )
 1347: 			{
 1348: 			  index++;
 1349: 			  flags |= FLAGS_BASE_PARAMETER;
 1350: 			  base = TrioGetPosition(format, &index);
 1351: 			  if (base == NO_POSITION)
 1352: 			    {
 1353: 			      parameterPosition++;
 1354: 			      if (positional)
 1355: 				base = parameterPosition;
 1356: 			      else
 1357: 				{
 1358: 				  base = currentParam;
 1359: 				  currentParam = base + 1;
 1360: 				}
 1361: 			    }
 1362: 			  else
 1363: 			    {
 1364: 			      if (! positional)
 1365: 				currentParam = base + 1;
 1366: 			      if (base > maxParam)
 1367: 				maxParam = base;
 1368: 			    }
 1369: 			  if (currentParam > maxParam)
 1370: 			    maxParam = currentParam;
 1371: 			}
 1372: 		      else
 1373: 			{
 1374: 			  base = trio_to_long(&format[index],
 1375: 					      &tmpformat,
 1376: 					      BASE_DECIMAL);
 1377: 			  if (base > MAX_BASE)
 1378: 			    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1379: 			  index = (int)(tmpformat - format);
 1380: 			}
 1381: 		    }
 1382: 		  else
 1383: 		    {
 1384: 		      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1385: 		    }
 1386: 		  break; /* QUALIFIER_DOT */
 1387: 
 1388: #if defined(QUALIFIER_PARAM)
 1389: 		case QUALIFIER_PARAM:
 1390: 		  type = TYPE_PRINT;
 1391: 		  /* FALLTHROUGH */
 1392: #endif
 1393: 		case QUALIFIER_STAR:
 1394: 		  /* This has different meanings for print and scan */
 1395: 		  if (TYPE_PRINT == type)
 1396: 		    {
 1397: 		      /* Read with from parameter */
 1398: 		      flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
 1399: 		      width = TrioGetPosition(format, &index);
 1400: 		      if (width == NO_POSITION)
 1401: 			{
 1402: 			  parameterPosition++;
 1403: 			  if (positional)
 1404: 			    width = parameterPosition;
 1405: 			  else
 1406: 			    {
 1407: 			      width = currentParam;
 1408: 			      currentParam = width + 1;
 1409: 			    }
 1410: 			}
 1411: 		      else
 1412: 			{
 1413: 			  if (! positional)
 1414: 			    currentParam = width + 1;
 1415: 			  if (width > maxParam)
 1416: 			    maxParam = width;
 1417: 			}
 1418: 		      if (currentParam > maxParam)
 1419: 			maxParam = currentParam;
 1420: 		    }
 1421: 		  else
 1422: 		    {
 1423: 		      /* Scan, but do not store result */
 1424: 		      flags |= FLAGS_IGNORE;
 1425: 		    }
 1426: 
 1427: 		  break; /* QUALIFIER_STAR */
 1428: 
 1429: 		case '0':
 1430: 		  if (! (flags & FLAGS_LEFTADJUST))
 1431: 		    flags |= FLAGS_NILPADDING;
 1432: 		  /* FALLTHROUGH */
 1433: 		case '1': case '2': case '3': case '4':
 1434: 		case '5': case '6': case '7': case '8': case '9':
 1435: 		  flags |= FLAGS_WIDTH;
 1436: 		  /* &format[index - 1] is used to "rewind" the read
 1437: 		   * character from format
 1438: 		   */
 1439: 		  width = trio_to_long(&format[index - 1],
 1440: 				       &tmpformat,
 1441: 				       BASE_DECIMAL);
 1442: 		  index = (int)(tmpformat - format);
 1443: 		  break;
 1444: 
 1445: 		case QUALIFIER_SHORT:
 1446: 		  if (flags & FLAGS_SHORTSHORT)
 1447: 		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1448: 		  else if (flags & FLAGS_SHORT)
 1449: 		    flags |= FLAGS_SHORTSHORT;
 1450: 		  else
 1451: 		    flags |= FLAGS_SHORT;
 1452: 		  break;
 1453: 
 1454: 		case QUALIFIER_LONG:
 1455: 		  if (flags & FLAGS_QUAD)
 1456: 		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1457: 		  else if (flags & FLAGS_LONG)
 1458: 		    flags |= FLAGS_QUAD;
 1459: 		  else
 1460: 		    flags |= FLAGS_LONG;
 1461: 		  break;
 1462: 
 1463: 		case QUALIFIER_LONG_UPPER:
 1464: 		  flags |= FLAGS_LONGDOUBLE;
 1465: 		  break;
 1466: 
 1467: #if defined(QUALIFIER_SIZE_T)
 1468: 		case QUALIFIER_SIZE_T:
 1469: 		  flags |= FLAGS_SIZE_T;
 1470: 		  /* Modify flags for later truncation of number */
 1471: 		  if (sizeof(size_t) == sizeof(trio_ulonglong_t))
 1472: 		    flags |= FLAGS_QUAD;
 1473: 		  else if (sizeof(size_t) == sizeof(long))
 1474: 		    flags |= FLAGS_LONG;
 1475: 		  break;
 1476: #endif
 1477: 
 1478: #if defined(QUALIFIER_PTRDIFF_T)
 1479: 		case QUALIFIER_PTRDIFF_T:
 1480: 		  flags |= FLAGS_PTRDIFF_T;
 1481: 		  if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
 1482: 		    flags |= FLAGS_QUAD;
 1483: 		  else if (sizeof(ptrdiff_t) == sizeof(long))
 1484: 		    flags |= FLAGS_LONG;
 1485: 		  break;
 1486: #endif
 1487: 
 1488: #if defined(QUALIFIER_INTMAX_T)
 1489: 		case QUALIFIER_INTMAX_T:
 1490: 		  flags |= FLAGS_INTMAX_T;
 1491: 		  if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
 1492: 		    flags |= FLAGS_QUAD;
 1493: 		  else if (sizeof(trio_intmax_t) == sizeof(long))
 1494: 		    flags |= FLAGS_LONG;
 1495: 		  break;
 1496: #endif
 1497: 
 1498: #if defined(QUALIFIER_QUAD)
 1499: 		case QUALIFIER_QUAD:
 1500: 		  flags |= FLAGS_QUAD;
 1501: 		  break;
 1502: #endif
 1503: 
 1504: #if defined(QUALIFIER_FIXED_SIZE)
 1505: 		case QUALIFIER_FIXED_SIZE:
 1506: 		  if (flags & FLAGS_FIXED_SIZE)
 1507: 		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1508: 
 1509: 		  if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
 1510: 			       FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
 1511: 		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1512: 
 1513: 		  if ((format[index] == '6') &&
 1514: 		      (format[index + 1] == '4'))
 1515: 		    {
 1516: 		      varsize = sizeof(trio_int64_t);
 1517: 		      index += 2;
 1518: 		    }
 1519: 		  else if ((format[index] == '3') &&
 1520: 			   (format[index + 1] == '2'))
 1521: 		    {
 1522: 		      varsize = sizeof(trio_int32_t);
 1523: 		      index += 2;
 1524: 		    }
 1525: 		  else if ((format[index] == '1') &&
 1526: 			   (format[index + 1] == '6'))
 1527: 		    {
 1528: 		      varsize = sizeof(trio_int16_t);
 1529: 		      index += 2;
 1530: 		    }
 1531: 		  else if (format[index] == '8')
 1532: 		    {
 1533: 		      varsize = sizeof(trio_int8_t);
 1534: 		      index++;
 1535: 		    }
 1536: 		  else
 1537: 		    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1538: 		  
 1539: 		  flags |= FLAGS_FIXED_SIZE;
 1540: 		  break;
 1541: #endif
 1542: 
 1543: #if defined(QUALIFIER_WIDECHAR)
 1544: 		case QUALIFIER_WIDECHAR:
 1545: 		  flags |= FLAGS_WIDECHAR;
 1546: 		  break;
 1547: #endif
 1548: 
 1549: #if defined(QUALIFIER_SIZE_T_UPPER)
 1550: 		case QUALIFIER_SIZE_T_UPPER:
 1551: 		  break;
 1552: #endif
 1553: 
 1554: #if defined(QUALIFIER_QUOTE)
 1555: 		case QUALIFIER_QUOTE:
 1556: 		  flags |= FLAGS_QUOTE;
 1557: 		  break;
 1558: #endif
 1559: 
 1560: #if defined(QUALIFIER_STICKY)
 1561: 		case QUALIFIER_STICKY:
 1562: 		  flags |= FLAGS_STICKY;
 1563: 		  gotSticky = TRUE;
 1564: 		  break;
 1565: #endif
 1566: 		  
 1567: #if defined(QUALIFIER_VARSIZE)
 1568: 		case QUALIFIER_VARSIZE:
 1569: 		  flags |= FLAGS_VARSIZE_PARAMETER;
 1570: 		  parameterPosition++;
 1571: 		  if (positional)
 1572: 		    varsize = parameterPosition;
 1573: 		  else
 1574: 		    {
 1575: 		      varsize = currentParam;
 1576: 		      currentParam = varsize + 1;
 1577: 		    }
 1578: 		  if (currentParam > maxParam)
 1579: 		    maxParam = currentParam;
 1580: 		  break;
 1581: #endif
 1582: 
 1583: #if defined(QUALIFIER_ROUNDING_UPPER)
 1584: 		case QUALIFIER_ROUNDING_UPPER:
 1585: 		  flags |= FLAGS_ROUNDING;
 1586: 		  break;
 1587: #endif
 1588: 
 1589: 		default:
 1590: 		  /* Bail out completely to make the error more obvious */
 1591:                   return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1592: 		}
 1593: 	    } /* while qualifier */
 1594: 
 1595: 	  /*
 1596: 	   * Parameters only need the type and value. The value is
 1597: 	   * read later.
 1598: 	   */
 1599: 	  if (flags & FLAGS_WIDTH_PARAMETER)
 1600: 	    {
 1601: 	      usedEntries[width] += 1;
 1602: 	      parameters[pos].type = FORMAT_PARAMETER;
 1603: 	      parameters[pos].flags = 0;
 1604: 	      indices[width] = pos;
 1605: 	      width = pos++;
 1606: 	    }
 1607: 	  if (flags & FLAGS_PRECISION_PARAMETER)
 1608: 	    {
 1609: 	      usedEntries[precision] += 1;
 1610: 	      parameters[pos].type = FORMAT_PARAMETER;
 1611: 	      parameters[pos].flags = 0;
 1612: 	      indices[precision] = pos;
 1613: 	      precision = pos++;
 1614: 	    }
 1615: 	  if (flags & FLAGS_BASE_PARAMETER)
 1616: 	    {
 1617: 	      usedEntries[base] += 1;
 1618: 	      parameters[pos].type = FORMAT_PARAMETER;
 1619: 	      parameters[pos].flags = 0;
 1620: 	      indices[base] = pos;
 1621: 	      base = pos++;
 1622: 	    }
 1623: 	  if (flags & FLAGS_VARSIZE_PARAMETER)
 1624: 	    {
 1625: 	      usedEntries[varsize] += 1;
 1626: 	      parameters[pos].type = FORMAT_PARAMETER;
 1627: 	      parameters[pos].flags = 0;
 1628: 	      indices[varsize] = pos;
 1629: 	      varsize = pos++;
 1630: 	    }
 1631: 	  
 1632: 	  indices[currentParam] = pos;
 1633: 	  
 1634: 	  switch (format[index++])
 1635: 	    {
 1636: #if defined(SPECIFIER_CHAR_UPPER)
 1637: 	    case SPECIFIER_CHAR_UPPER:
 1638: 	      flags |= FLAGS_WIDECHAR;
 1639: 	      /* FALLTHROUGH */
 1640: #endif
 1641: 	    case SPECIFIER_CHAR:
 1642: 	      if (flags & FLAGS_LONG)
 1643: 		flags |= FLAGS_WIDECHAR;
 1644: 	      else if (flags & FLAGS_SHORT)
 1645: 		flags &= ~FLAGS_WIDECHAR;
 1646: 	      parameters[pos].type = FORMAT_CHAR;
 1647: 	      break;
 1648: 
 1649: #if defined(SPECIFIER_STRING_UPPER)
 1650: 	    case SPECIFIER_STRING_UPPER:
 1651: 	      flags |= FLAGS_WIDECHAR;
 1652: 	      /* FALLTHROUGH */
 1653: #endif
 1654: 	    case SPECIFIER_STRING:
 1655: 	      if (flags & FLAGS_LONG)
 1656: 		flags |= FLAGS_WIDECHAR;
 1657: 	      else if (flags & FLAGS_SHORT)
 1658: 		flags &= ~FLAGS_WIDECHAR;
 1659: 	      parameters[pos].type = FORMAT_STRING;
 1660: 	      break;
 1661: 
 1662: 	    case SPECIFIER_GROUP:
 1663: 	      if (TYPE_SCAN == type)
 1664: 		{
 1665: 		  int depth = 1;
 1666: 		  parameters[pos].type = FORMAT_GROUP;
 1667: 		  if (format[index] == QUALIFIER_CIRCUMFLEX)
 1668: 		    index++;
 1669: 		  if (format[index] == SPECIFIER_UNGROUP)
 1670: 		    index++;
 1671: 		  if (format[index] == QUALIFIER_MINUS)
 1672: 		    index++;
 1673: 		  /* Skip nested brackets */
 1674: 		  while (format[index] != NIL)
 1675: 		    {
 1676: 		      if (format[index] == SPECIFIER_GROUP)
 1677: 			{
 1678: 			  depth++;
 1679: 			}
 1680: 		      else if (format[index] == SPECIFIER_UNGROUP)
 1681: 			{
 1682: 			  if (--depth <= 0)
 1683: 			    {
 1684: 			      index++;
 1685: 			      break;
 1686: 			    }
 1687: 			}
 1688: 		      index++;
 1689: 		    }
 1690: 		}
 1691: 	      break;
 1692: 	      
 1693: 	    case SPECIFIER_INTEGER:
 1694: 	      parameters[pos].type = FORMAT_INT;
 1695: 	      break;
 1696: 	      
 1697: 	    case SPECIFIER_UNSIGNED:
 1698: 	      flags |= FLAGS_UNSIGNED;
 1699: 	      parameters[pos].type = FORMAT_INT;
 1700: 	      break;
 1701: 
 1702: 	    case SPECIFIER_DECIMAL:
 1703: 	      /* Disable base modifier */
 1704: 	      flags &= ~FLAGS_BASE_PARAMETER;
 1705: 	      base = BASE_DECIMAL;
 1706: 	      parameters[pos].type = FORMAT_INT;
 1707: 	      break;
 1708: 
 1709: 	    case SPECIFIER_OCTAL:
 1710: 	      flags |= FLAGS_UNSIGNED;
 1711: 	      flags &= ~FLAGS_BASE_PARAMETER;
 1712: 	      base = BASE_OCTAL;
 1713: 	      parameters[pos].type = FORMAT_INT;
 1714: 	      break;
 1715: 
 1716: #if defined(SPECIFIER_BINARY)
 1717: 	    case SPECIFIER_BINARY_UPPER:
 1718: 	      flags |= FLAGS_UPPER;
 1719: 	      /* FALLTHROUGH */
 1720: 	    case SPECIFIER_BINARY:
 1721: 	      flags |= FLAGS_NILPADDING;
 1722: 	      flags &= ~FLAGS_BASE_PARAMETER;
 1723: 	      base = BASE_BINARY;
 1724: 	      parameters[pos].type = FORMAT_INT;
 1725: 	      break;
 1726: #endif
 1727: 
 1728: 	    case SPECIFIER_HEX_UPPER:
 1729: 	      flags |= FLAGS_UPPER;
 1730: 	      /* FALLTHROUGH */
 1731: 	    case SPECIFIER_HEX:
 1732: 	      flags |= FLAGS_UNSIGNED;
 1733: 	      flags &= ~FLAGS_BASE_PARAMETER;
 1734: 	      base = BASE_HEX;
 1735: 	      parameters[pos].type = FORMAT_INT;
 1736: 	      break;
 1737: 
 1738: 	    case SPECIFIER_FLOAT_E_UPPER:
 1739: 	      flags |= FLAGS_UPPER;
 1740: 	      /* FALLTHROUGH */
 1741: 	    case SPECIFIER_FLOAT_E:
 1742: 	      flags |= FLAGS_FLOAT_E;
 1743: 	      parameters[pos].type = FORMAT_DOUBLE;
 1744: 	      break;
 1745: 
 1746: 	    case SPECIFIER_FLOAT_G_UPPER:
 1747: 	      flags |= FLAGS_UPPER;
 1748: 	      /* FALLTHROUGH */
 1749: 	    case SPECIFIER_FLOAT_G:
 1750: 	      flags |= FLAGS_FLOAT_G;
 1751: 	      parameters[pos].type = FORMAT_DOUBLE;
 1752: 	      break;
 1753: 
 1754: 	    case SPECIFIER_FLOAT_F_UPPER:
 1755: 	      flags |= FLAGS_UPPER;
 1756: 	      /* FALLTHROUGH */
 1757: 	    case SPECIFIER_FLOAT_F:
 1758: 	      parameters[pos].type = FORMAT_DOUBLE;
 1759: 	      break;
 1760: 
 1761: 	    case SPECIFIER_POINTER:
 1762: 	      if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
 1763: 		flags |= FLAGS_QUAD;
 1764: 	      else if (sizeof(trio_pointer_t) == sizeof(long))
 1765: 		flags |= FLAGS_LONG;
 1766: 	      parameters[pos].type = FORMAT_POINTER;
 1767: 	      break;
 1768: 
 1769: 	    case SPECIFIER_COUNT:
 1770: 	      parameters[pos].type = FORMAT_COUNT;
 1771: 	      break;
 1772: 
 1773: #if defined(SPECIFIER_HEXFLOAT)
 1774: # if defined(SPECIFIER_HEXFLOAT_UPPER)
 1775: 	    case SPECIFIER_HEXFLOAT_UPPER:
 1776: 	      flags |= FLAGS_UPPER;
 1777: 	      /* FALLTHROUGH */
 1778: # endif
 1779: 	    case SPECIFIER_HEXFLOAT:
 1780: 	      base = BASE_HEX;
 1781: 	      parameters[pos].type = FORMAT_DOUBLE;
 1782: 	      break;
 1783: #endif
 1784: 
 1785: #if defined(FORMAT_ERRNO)
 1786: 	    case SPECIFIER_ERRNO:
 1787: 	      parameters[pos].type = FORMAT_ERRNO;
 1788: 	      break;
 1789: #endif
 1790: 
 1791: #if defined(SPECIFIER_USER_DEFINED_BEGIN)
 1792: 	    case SPECIFIER_USER_DEFINED_BEGIN:
 1793: 	      {
 1794: 		unsigned int max;
 1795: 		int without_namespace = TRUE;
 1796: 		
 1797: 		parameters[pos].type = FORMAT_USER_DEFINED;
 1798: 		parameters[pos].user_name[0] = NIL;
 1799: 		tmpformat = (char *)&format[index];
 1800: 	      
 1801: 		while ((ch = format[index]))
 1802: 		  {
 1803: 		    index++;
 1804: 		    if (ch == SPECIFIER_USER_DEFINED_END)
 1805: 		      {
 1806: 			if (without_namespace)
 1807: 			  {
 1808: 			    /* We must get the handle first */
 1809: 			    parameters[pos].type = FORMAT_PARAMETER;
 1810: 			    parameters[pos].indexAfterSpecifier = index;
 1811: 			    parameters[pos].flags = FLAGS_USER_DEFINED;
 1812: 			    /* Adjust parameters for insertion of new one */
 1813: 			    pos++;
 1814: 			    usedEntries[currentParam] += 1;
 1815: 			    parameters[pos].type = FORMAT_USER_DEFINED;
 1816: 			    currentParam++;
 1817: 			    indices[currentParam] = pos;
 1818: 			    if (currentParam > maxParam)
 1819: 			      maxParam = currentParam;
 1820: 			  }
 1821: 			/* Copy the user data */
 1822: 			max = (unsigned int)(&format[index] - tmpformat);
 1823: 			if (max > MAX_USER_DATA)
 1824: 			  max = MAX_USER_DATA;
 1825: 			trio_copy_max(parameters[pos].user_data,
 1826: 				      max,
 1827: 				      tmpformat);
 1828: 			break; /* while */
 1829: 		      }
 1830: 		    if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
 1831: 		      {
 1832: 			without_namespace = FALSE;
 1833: 			/* Copy the namespace for later looking-up */
 1834: 			max = (int)(&format[index] - tmpformat);
 1835: 			if (max > MAX_USER_NAME)
 1836: 			  max = MAX_USER_NAME;
 1837: 			trio_copy_max(parameters[pos].user_name,
 1838: 				      max,
 1839: 				      tmpformat);
 1840: 			tmpformat = (char *)&format[index];
 1841: 		      }
 1842: 		  }
 1843: 		if (ch != SPECIFIER_USER_DEFINED_END)
 1844: 		  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1845: 	      }
 1846: 	      break;
 1847: #endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
 1848: 	      
 1849: 	    default:
 1850: 	      /* Bail out completely to make the error more obvious */
 1851:               return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 1852: 	    }
 1853: 
 1854: 	  /*  Count the number of times this entry has been used */
 1855: 	  usedEntries[currentParam] += 1;
 1856: 	  
 1857: 	  /* Find last sticky parameters */
 1858: 	  if (gotSticky && !(flags & FLAGS_STICKY))
 1859: 	    {
 1860: 	      for (i = pos - 1; i >= 0; i--)
 1861: 		{
 1862: 		  if (parameters[i].type == FORMAT_PARAMETER)
 1863: 		    continue;
 1864: 		  if ((parameters[i].flags & FLAGS_STICKY) &&
 1865: 		      (parameters[i].type == parameters[pos].type))
 1866: 		    {
 1867: 		      /* Do not overwrite current qualifiers */
 1868: 		      flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
 1869: 		      if (width == NO_WIDTH)
 1870: 			width = parameters[i].width;
 1871: 		      if (precision == NO_PRECISION)
 1872: 			precision = parameters[i].precision;
 1873: 		      if (base == NO_BASE)
 1874: 			base = parameters[i].base;
 1875: 		      break;
 1876: 		    }
 1877: 		}
 1878: 	    }
 1879: 	  
 1880: 	  parameters[pos].indexAfterSpecifier = index;
 1881: 	  parameters[pos].flags = flags;
 1882: 	  parameters[pos].width = width;
 1883: 	  parameters[pos].precision = precision;
 1884: 	  parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
 1885: 	  parameters[pos].varsize = varsize;
 1886: 	  pos++;
 1887: 	  
 1888: 	  if (! positional)
 1889: 	    parameterPosition++;
 1890: 	  
 1891: 	} /* if identifier */
 1892:       
 1893:     } /* while format characters left */
 1894: 
 1895:   for (num = 0; num <= maxParam; num++)
 1896:     {
 1897:       if (usedEntries[num] != 1)
 1898: 	{
 1899: 	  if (usedEntries[num] == 0) /* gap detected */
 1900: 	    return TRIO_ERROR_RETURN(TRIO_EGAP, num);
 1901: 	  else /* double references detected */
 1902: 	    return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
 1903: 	}
 1904:       
 1905:       i = indices[num];
 1906: 
 1907:       /*
 1908:        * FORMAT_PARAMETERS are only present if they must be read,
 1909:        * so it makes no sense to check the ignore flag (besides,
 1910:        * the flags variable is not set for that particular type)
 1911:        */
 1912:       if ((parameters[i].type != FORMAT_PARAMETER) &&
 1913: 	  (parameters[i].flags & FLAGS_IGNORE))
 1914: 	continue; /* for all arguments */
 1915: 
 1916:       /*
 1917:        * The stack arguments are read according to ANSI C89
 1918:        * default argument promotions:
 1919:        *
 1920:        *  char           = int
 1921:        *  short          = int
 1922:        *  unsigned char  = unsigned int
 1923:        *  unsigned short = unsigned int
 1924:        *  float          = double
 1925:        *
 1926:        * In addition to the ANSI C89 these types are read (the
 1927:        * default argument promotions of C99 has not been
 1928:        * considered yet)
 1929:        *
 1930:        *  long long
 1931:        *  long double
 1932:        *  size_t
 1933:        *  ptrdiff_t
 1934:        *  intmax_t
 1935:        */
 1936:       switch (parameters[i].type)
 1937: 	{
 1938: 	case FORMAT_GROUP:
 1939: 	case FORMAT_STRING:
 1940: #if TRIO_WIDECHAR
 1941: 	  if (flags & FLAGS_WIDECHAR)
 1942: 	    {
 1943: 	      parameters[i].data.wstring = (argarray == NULL)
 1944: 		? va_arg(*arglist, trio_wchar_t *)
 1945: 		: (trio_wchar_t *)(argarray[num]);
 1946: 	    }
 1947: 	  else
 1948: #endif
 1949: 	    {
 1950: 	      parameters[i].data.string = (argarray == NULL)
 1951: 		? va_arg(*arglist, char *)
 1952: 		: (char *)(argarray[num]);
 1953: 	    }
 1954: 	  break;
 1955: 
 1956: #if defined(FORMAT_USER_DEFINED)
 1957: 	case FORMAT_USER_DEFINED:
 1958: #endif
 1959: 	case FORMAT_POINTER:
 1960: 	case FORMAT_COUNT:
 1961: 	case FORMAT_UNKNOWN:
 1962: 	  parameters[i].data.pointer = (argarray == NULL)
 1963: 	    ? va_arg(*arglist, trio_pointer_t )
 1964: 	    : argarray[num];
 1965: 	  break;
 1966: 
 1967: 	case FORMAT_CHAR:
 1968: 	case FORMAT_INT:
 1969: 	  if (TYPE_SCAN == type)
 1970: 	    {
 1971:               if (argarray == NULL)
 1972:                 parameters[i].data.pointer = 
 1973:                   (trio_pointer_t)va_arg(*arglist, trio_pointer_t);
 1974:               else
 1975:                 {
 1976:                   if (parameters[i].type == FORMAT_CHAR)
 1977:                     parameters[i].data.pointer =
 1978:                       (trio_pointer_t)((char *)argarray[num]);
 1979:                   else if (parameters[i].flags & FLAGS_SHORT)
 1980:                     parameters[i].data.pointer =
 1981:                       (trio_pointer_t)((short *)argarray[num]);
 1982:                   else
 1983:                     parameters[i].data.pointer =
 1984:                       (trio_pointer_t)((int *)argarray[num]);
 1985:                 }
 1986: 	    }
 1987: 	  else
 1988: 	    {
 1989: #if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
 1990: 	      if (parameters[i].flags
 1991: 		  & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
 1992: 		{
 1993: 		  if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
 1994: 		    {
 1995: 		      /*
 1996: 		       * Variable sizes are mapped onto the fixed sizes, in
 1997: 		       * accordance with integer promotion.
 1998: 		       *
 1999: 		       * Please note that this may not be portable, as we
 2000: 		       * only guess the size, not the layout of the numbers.
 2001: 		       * For example, if int is little-endian, and long is
 2002: 		       * big-endian, then this will fail.
 2003: 		       */
 2004: 		      varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
 2005: 		    }
 2006: 		  else
 2007: 		    {
 2008: 		      /* Used for the I<bits> modifiers */
 2009: 		      varsize = parameters[i].varsize;
 2010: 		    }
 2011: 		  parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
 2012: 		  
 2013: 		  if (varsize <= (int)sizeof(int))
 2014: 		    ;
 2015: 		  else if (varsize <= (int)sizeof(long))
 2016: 		    parameters[i].flags |= FLAGS_LONG;
 2017: #if defined(QUALIFIER_INTMAX_T)
 2018: 		  else if (varsize <= (int)sizeof(trio_longlong_t))
 2019: 		    parameters[i].flags |= FLAGS_QUAD;
 2020: 		  else
 2021: 		    parameters[i].flags |= FLAGS_INTMAX_T;
 2022: #else
 2023: 		  else
 2024: 		    parameters[i].flags |= FLAGS_QUAD;
 2025: #endif
 2026: 		}
 2027: #endif /* defined(QUALIFIER_VARSIZE) */
 2028: #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
 2029: 	      if (parameters[i].flags & FLAGS_SIZE_T)
 2030: 		parameters[i].data.number.as_unsigned = (argarray == NULL)
 2031: 		  ? (trio_uintmax_t)va_arg(*arglist, size_t)
 2032: 		  : (trio_uintmax_t)(*((size_t *)argarray[num]));
 2033: 	      else
 2034: #endif
 2035: #if defined(QUALIFIER_PTRDIFF_T)
 2036: 	      if (parameters[i].flags & FLAGS_PTRDIFF_T)
 2037: 		parameters[i].data.number.as_unsigned = (argarray == NULL)
 2038: 		  ? (trio_uintmax_t)va_arg(*arglist, ptrdiff_t)
 2039: 		  : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
 2040: 	      else
 2041: #endif
 2042: #if defined(QUALIFIER_INTMAX_T)
 2043: 	      if (parameters[i].flags & FLAGS_INTMAX_T)
 2044: 		parameters[i].data.number.as_unsigned = (argarray == NULL)
 2045: 		  ? (trio_uintmax_t)va_arg(*arglist, trio_intmax_t)
 2046: 		  : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
 2047: 	      else
 2048: #endif
 2049: 	      if (parameters[i].flags & FLAGS_QUAD)
 2050: 		parameters[i].data.number.as_unsigned = (argarray == NULL)
 2051: 		  ? (trio_uintmax_t)va_arg(*arglist, trio_ulonglong_t)
 2052: 		  : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
 2053: 	      else if (parameters[i].flags & FLAGS_LONG)
 2054: 		parameters[i].data.number.as_unsigned = (argarray == NULL)
 2055: 		  ? (trio_uintmax_t)va_arg(*arglist, long)
 2056: 		  : (trio_uintmax_t)(*((long *)argarray[num]));
 2057: 	      else
 2058: 		{
 2059: 		  if (argarray == NULL)
 2060: 		    parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(*arglist, int);
 2061: 		  else
 2062: 		    {
 2063: 		      if (parameters[i].type == FORMAT_CHAR)
 2064: 			parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
 2065: 		      else if (parameters[i].flags & FLAGS_SHORT)
 2066: 			parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
 2067: 		      else
 2068: 			parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
 2069: 		    }
 2070: 		}
 2071: 	    }
 2072: 	  break;
 2073: 
 2074: 	case FORMAT_PARAMETER:
 2075: 	  /*
 2076: 	   * The parameter for the user-defined specifier is a pointer,
 2077: 	   * whereas the rest (width, precision, base) uses an integer.
 2078: 	   */
 2079: 	  if (parameters[i].flags & FLAGS_USER_DEFINED)
 2080: 	    parameters[i].data.pointer = (argarray == NULL)
 2081: 	      ? va_arg(*arglist, trio_pointer_t )
 2082: 	      : argarray[num];
 2083: 	  else
 2084: 	    parameters[i].data.number.as_unsigned = (argarray == NULL)
 2085: 	      ? (trio_uintmax_t)va_arg(*arglist, int)
 2086: 	      : (trio_uintmax_t)(*((int *)argarray[num]));
 2087: 	  break;
 2088: 
 2089: 	case FORMAT_DOUBLE:
 2090: 	  if (TYPE_SCAN == type)
 2091: 	    {
 2092: 	      if (parameters[i].flags & FLAGS_LONGDOUBLE)
 2093: 		parameters[i].data.longdoublePointer = (argarray == NULL)
 2094: 		  ? va_arg(*arglist, trio_long_double_t *)
 2095: 		  : (trio_long_double_t *)argarray[num];
 2096: 	      else
 2097:                 {
 2098: 		  if (parameters[i].flags & FLAGS_LONG)
 2099: 		    parameters[i].data.doublePointer = (argarray == NULL)
 2100: 		      ? va_arg(*arglist, double *)
 2101: 		      : (double *)argarray[num];
 2102: 		  else
 2103: 		    parameters[i].data.doublePointer = (argarray == NULL)
 2104: 		      ? (double *)va_arg(*arglist, float *)
 2105: 		      : (double *)((float *)argarray[num]);
 2106:                 }
 2107: 	    }
 2108: 	  else
 2109: 	    {
 2110: 	      if (parameters[i].flags & FLAGS_LONGDOUBLE)
 2111: 		parameters[i].data.longdoubleNumber = (argarray == NULL)
 2112: 		  ? va_arg(*arglist, trio_long_double_t)
 2113: 		  : (trio_long_double_t)(*((trio_long_double_t *)argarray[num]));
 2114: 	      else
 2115: 		{
 2116: 		  if (argarray == NULL)
 2117: 		    parameters[i].data.longdoubleNumber =
 2118: 		      (trio_long_double_t)va_arg(*arglist, double);
 2119: 		  else
 2120: 		    {
 2121: 		      if (parameters[i].flags & FLAGS_SHORT)
 2122: 			parameters[i].data.longdoubleNumber =
 2123: 			  (trio_long_double_t)(*((float *)argarray[num]));
 2124: 		      else
 2125: 			parameters[i].data.longdoubleNumber =
 2126: 			  (trio_long_double_t)(*((double *)argarray[num]));
 2127: 		    }
 2128: 		}
 2129: 	    }
 2130: 	  break;
 2131: 
 2132: #if defined(FORMAT_ERRNO)
 2133: 	case FORMAT_ERRNO:
 2134: 	  parameters[i].data.errorNumber = save_errno;
 2135: 	  break;
 2136: #endif
 2137: 
 2138: 	default:
 2139: 	  break;
 2140: 	}
 2141:     } /* for all specifiers */
 2142:   return num;
 2143: }
 2144: 
 2145: 
 2146: /*************************************************************************
 2147:  *
 2148:  * FORMATTING
 2149:  *
 2150:  ************************************************************************/
 2151: 
 2152: 
 2153: /*************************************************************************
 2154:  * TrioWriteNumber
 2155:  *
 2156:  * Description:
 2157:  *  Output a number.
 2158:  *  The complexity of this function is a result of the complexity
 2159:  *  of the dependencies of the flags.
 2160:  */
 2161: TRIO_PRIVATE void
 2162: TrioWriteNumber
 2163: TRIO_ARGS6((self, number, flags, width, precision, base),
 2164: 	   trio_class_t *self,
 2165: 	   trio_uintmax_t number,
 2166: 	   trio_flags_t flags,
 2167: 	   int width,
 2168: 	   int precision,
 2169: 	   int base)
 2170: {
 2171:   BOOLEAN_T isNegative;
 2172:   BOOLEAN_T isNumberZero;
 2173:   BOOLEAN_T isPrecisionZero;
 2174:   BOOLEAN_T ignoreNumber;
 2175:   char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
 2176:   char *bufferend;
 2177:   char *pointer;
 2178:   TRIO_CONST char *digits;
 2179:   int i;
 2180:   int length;
 2181:   char *p;
 2182:   int count;
 2183: 
 2184:   assert(VALID(self));
 2185:   assert(VALID(self->OutStream));
 2186:   assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
 2187: 
 2188:   digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
 2189:   if (base == NO_BASE)
 2190:     base = BASE_DECIMAL;
 2191: 
 2192:   isNumberZero = (number == 0);
 2193:   isPrecisionZero = (precision == 0);
 2194:   ignoreNumber = (isNumberZero
 2195: 		  && isPrecisionZero
 2196: 		  && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));
 2197: 
 2198:   if (flags & FLAGS_UNSIGNED)
 2199:     {
 2200:       isNegative = FALSE;
 2201:       flags &= ~FLAGS_SHOWSIGN;
 2202:     }
 2203:   else
 2204:     {
 2205:       isNegative = ((trio_intmax_t)number < 0);
 2206:       if (isNegative)
 2207: 	number = -((trio_intmax_t)number);
 2208:     }
 2209: 
 2210:   if (flags & FLAGS_QUAD)
 2211:     number &= (trio_ulonglong_t)-1;
 2212:   else if (flags & FLAGS_LONG)
 2213:     number &= (unsigned long)-1;
 2214:   else
 2215:     number &= (unsigned int)-1;
 2216:   
 2217:   /* Build number */
 2218:   pointer = bufferend = &buffer[sizeof(buffer) - 1];
 2219:   *pointer-- = NIL;
 2220:   for (i = 1; i < (int)sizeof(buffer); i++)
 2221:     {
 2222:       *pointer-- = digits[number % base];
 2223:       number /= base;
 2224:       if (number == 0)
 2225: 	break;
 2226: 
 2227:       if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
 2228: 	{
 2229: 	  /*
 2230: 	   * We are building the number from the least significant
 2231: 	   * to the most significant digit, so we have to copy the
 2232: 	   * thousand separator backwards
 2233: 	   */
 2234: 	  length = internalThousandSeparatorLength;
 2235: 	  if (((int)(pointer - buffer) - length) > 0)
 2236: 	    {
 2237: 	      p = &internalThousandSeparator[length - 1];
 2238: 	      while (length-- > 0)
 2239: 		*pointer-- = *p--;
 2240: 	    }
 2241: 	}
 2242:     }
 2243: 
 2244:   if (! ignoreNumber)
 2245:     {
 2246:       /* Adjust width */
 2247:       width -= (bufferend - pointer) - 1;
 2248:     }
 2249: 
 2250:   /* Adjust precision */
 2251:   if (NO_PRECISION != precision)
 2252:     {
 2253:       precision -= (bufferend - pointer) - 1;
 2254:       if (precision < 0)
 2255: 	precision = 0;
 2256:       flags |= FLAGS_NILPADDING;
 2257:     }
 2258: 
 2259:   /* Calculate padding */
 2260:   count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION)))
 2261:     ? precision
 2262:     : 0;
 2263:   
 2264:   /* Adjust width further */
 2265:   if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
 2266:     width--;
 2267:   if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
 2268:     {
 2269:       switch (base)
 2270: 	{
 2271: 	case BASE_BINARY:
 2272: 	case BASE_HEX:
 2273: 	  width -= 2;
 2274: 	  break;
 2275: 	case BASE_OCTAL:
 2276: 	  if (!(flags & FLAGS_NILPADDING) || (count == 0))
 2277: 	    width--;
 2278: 	  break;
 2279: 	default:
 2280: 	  break;
 2281: 	}
 2282:     }
 2283: 
 2284:   /* Output prefixes spaces if needed */
 2285:   if (! ((flags & FLAGS_LEFTADJUST) ||
 2286: 	 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
 2287:     {
 2288:       while (width-- > count)
 2289: 	self->OutStream(self, CHAR_ADJUST);
 2290:     }
 2291: 
 2292:   /* width has been adjusted for signs and alternatives */
 2293:   if (isNegative)
 2294:     self->OutStream(self, '-');
 2295:   else if (flags & FLAGS_SHOWSIGN)
 2296:     self->OutStream(self, '+');
 2297:   else if (flags & FLAGS_SPACE)
 2298:     self->OutStream(self, ' ');
 2299: 
 2300:   /* Prefix is not written when the value is zero */
 2301:   if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
 2302:     {
 2303:       switch (base)
 2304: 	{
 2305: 	case BASE_BINARY:
 2306: 	  self->OutStream(self, '0');
 2307: 	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
 2308: 	  break;
 2309: 
 2310: 	case BASE_OCTAL:
 2311: 	  if (!(flags & FLAGS_NILPADDING) || (count == 0))
 2312: 	    self->OutStream(self, '0');
 2313: 	  break;
 2314: 
 2315: 	case BASE_HEX:
 2316: 	  self->OutStream(self, '0');
 2317: 	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
 2318: 	  break;
 2319: 
 2320: 	default:
 2321: 	  break;
 2322: 	} /* switch base */
 2323:     }
 2324: 
 2325:   /* Output prefixed zero padding if needed */
 2326:   if (flags & FLAGS_NILPADDING)
 2327:     {
 2328:       if (precision == NO_PRECISION)
 2329: 	precision = width;
 2330:       while (precision-- > 0)
 2331: 	{
 2332: 	  self->OutStream(self, '0');
 2333: 	  width--;
 2334: 	}
 2335:     }
 2336: 
 2337:   if (! ignoreNumber)
 2338:     {
 2339:       /* Output the number itself */
 2340:       while (*(++pointer))
 2341: 	{
 2342: 	  self->OutStream(self, *pointer);
 2343: 	}
 2344:     }
 2345: 
 2346:   /* Output trailing spaces if needed */
 2347:   if (flags & FLAGS_LEFTADJUST)
 2348:     {
 2349:       while (width-- > 0)
 2350: 	self->OutStream(self, CHAR_ADJUST);
 2351:     }
 2352: }
 2353: 
 2354: /*************************************************************************
 2355:  * TrioWriteStringCharacter
 2356:  *
 2357:  * Description:
 2358:  *  Output a single character of a string
 2359:  */
 2360: TRIO_PRIVATE void
 2361: TrioWriteStringCharacter
 2362: TRIO_ARGS3((self, ch, flags),
 2363: 	   trio_class_t *self,
 2364: 	   int ch,
 2365: 	   trio_flags_t flags)
 2366: {
 2367:   if (flags & FLAGS_ALTERNATIVE)
 2368:     {
 2369:       if (! isprint(ch))
 2370: 	{
 2371: 	  /*
 2372: 	   * Non-printable characters are converted to C escapes or
 2373: 	   * \number, if no C escape exists.
 2374: 	   */
 2375: 	  self->OutStream(self, CHAR_BACKSLASH);
 2376: 	  switch (ch)
 2377: 	    {
 2378: 	    case '\007': self->OutStream(self, 'a'); break;
 2379: 	    case '\b': self->OutStream(self, 'b'); break;
 2380: 	    case '\f': self->OutStream(self, 'f'); break;
 2381: 	    case '\n': self->OutStream(self, 'n'); break;
 2382: 	    case '\r': self->OutStream(self, 'r'); break;
 2383: 	    case '\t': self->OutStream(self, 't'); break;
 2384: 	    case '\v': self->OutStream(self, 'v'); break;
 2385: 	    case '\\': self->OutStream(self, '\\'); break;
 2386: 	    default:
 2387: 	      self->OutStream(self, 'x');
 2388: 	      TrioWriteNumber(self, (trio_uintmax_t)ch,
 2389: 			      FLAGS_UNSIGNED | FLAGS_NILPADDING,
 2390: 			      2, 2, BASE_HEX);
 2391: 	      break;
 2392: 	    }
 2393: 	}
 2394:       else if (ch == CHAR_BACKSLASH)
 2395: 	{
 2396: 	  self->OutStream(self, CHAR_BACKSLASH);
 2397: 	  self->OutStream(self, CHAR_BACKSLASH);
 2398: 	}
 2399:       else
 2400: 	{
 2401: 	  self->OutStream(self, ch);
 2402: 	}
 2403:     }
 2404:   else
 2405:     {
 2406:       self->OutStream(self, ch);
 2407:     }
 2408: }
 2409: 
 2410: /*************************************************************************
 2411:  * TrioWriteString
 2412:  *
 2413:  * Description:
 2414:  *  Output a string
 2415:  */
 2416: TRIO_PRIVATE void
 2417: TrioWriteString
 2418: TRIO_ARGS5((self, string, flags, width, precision),
 2419: 	   trio_class_t *self,
 2420: 	   TRIO_CONST char *string,
 2421: 	   trio_flags_t flags,
 2422: 	   int width,
 2423: 	   int precision)
 2424: {
 2425:   int length;
 2426:   int ch;
 2427: 
 2428:   assert(VALID(self));
 2429:   assert(VALID(self->OutStream));
 2430: 
 2431:   if (string == NULL)
 2432:     {
 2433:       string = internalNullString;
 2434:       length = sizeof(internalNullString) - 1;
 2435:       /* Disable quoting for the null pointer */
 2436:       flags &= (~FLAGS_QUOTE);
 2437:       width = 0;
 2438:     }
 2439:   else
 2440:     {
 2441:       length = trio_length(string);
 2442:     }
 2443:   if ((NO_PRECISION != precision) &&
 2444:       (precision < length))
 2445:     {
 2446:       length = precision;
 2447:     }
 2448:   width -= length;
 2449: 
 2450:   if (flags & FLAGS_QUOTE)
 2451:     self->OutStream(self, CHAR_QUOTE);
 2452: 
 2453:   if (! (flags & FLAGS_LEFTADJUST))
 2454:     {
 2455:       while (width-- > 0)
 2456: 	self->OutStream(self, CHAR_ADJUST);
 2457:     }
 2458: 
 2459:   while (length-- > 0)
 2460:     {
 2461:       /* The ctype parameters must be an unsigned char (or EOF) */
 2462:       ch = (int)((unsigned char)(*string++));
 2463:       TrioWriteStringCharacter(self, ch, flags);
 2464:     }
 2465: 
 2466:   if (flags & FLAGS_LEFTADJUST)
 2467:     {
 2468:       while (width-- > 0)
 2469: 	self->OutStream(self, CHAR_ADJUST);
 2470:     }
 2471:   if (flags & FLAGS_QUOTE)
 2472:     self->OutStream(self, CHAR_QUOTE);
 2473: }
 2474: 
 2475: /*************************************************************************
 2476:  * TrioWriteWideStringCharacter
 2477:  *
 2478:  * Description:
 2479:  *  Output a wide string as a multi-byte sequence
 2480:  */
 2481: #if TRIO_WIDECHAR
 2482: TRIO_PRIVATE int
 2483: TrioWriteWideStringCharacter
 2484: TRIO_ARGS4((self, wch, flags, width),
 2485: 	   trio_class_t *self,
 2486: 	   trio_wchar_t wch,
 2487: 	   trio_flags_t flags,
 2488: 	   int width)
 2489: {
 2490:   int size;
 2491:   int i;
 2492:   int ch;
 2493:   char *string;
 2494:   char buffer[MB_LEN_MAX + 1];
 2495: 
 2496:   if (width == NO_WIDTH)
 2497:     width = sizeof(buffer);
 2498:   
 2499:   size = wctomb(buffer, wch);
 2500:   if ((size <= 0) || (size > width) || (buffer[0] == NIL))
 2501:     return 0;
 2502: 
 2503:   string = buffer;
 2504:   i = size;
 2505:   while ((width >= i) && (width-- > 0) && (i-- > 0))
 2506:     {
 2507:       /* The ctype parameters must be an unsigned char (or EOF) */
 2508:       ch = (int)((unsigned char)(*string++));
 2509:       TrioWriteStringCharacter(self, ch, flags);
 2510:     }
 2511:   return size;
 2512: }
 2513: #endif /* TRIO_WIDECHAR */
 2514: 
 2515: /*************************************************************************
 2516:  * TrioWriteWideString
 2517:  *
 2518:  * Description:
 2519:  *  Output a wide character string as a multi-byte string
 2520:  */
 2521: #if TRIO_WIDECHAR
 2522: TRIO_PRIVATE void
 2523: TrioWriteWideString
 2524: TRIO_ARGS5((self, wstring, flags, width, precision),
 2525: 	   trio_class_t *self,
 2526: 	   TRIO_CONST trio_wchar_t *wstring,
 2527: 	   trio_flags_t flags,
 2528: 	   int width,
 2529: 	   int precision)
 2530: {
 2531:   int length;
 2532:   int size;
 2533: 
 2534:   assert(VALID(self));
 2535:   assert(VALID(self->OutStream));
 2536: 
 2537: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 2538:   (void)mblen(NULL, 0);
 2539: #endif
 2540:   
 2541:   if (wstring == NULL)
 2542:     {
 2543:       TrioWriteString(self, NULL, flags, width, precision);
 2544:       return;
 2545:     }
 2546:   
 2547:   if (NO_PRECISION == precision)
 2548:     {
 2549:       length = INT_MAX;
 2550:     }
 2551:   else
 2552:     {
 2553:       length = precision;
 2554:       width -= length;
 2555:     }
 2556: 
 2557:   if (flags & FLAGS_QUOTE)
 2558:     self->OutStream(self, CHAR_QUOTE);
 2559: 
 2560:   if (! (flags & FLAGS_LEFTADJUST))
 2561:     {
 2562:       while (width-- > 0)
 2563: 	self->OutStream(self, CHAR_ADJUST);
 2564:     }
 2565: 
 2566:   while (length > 0)
 2567:     {
 2568:       size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
 2569:       if (size == 0)
 2570: 	break; /* while */
 2571:       length -= size;
 2572:     }
 2573: 
 2574:   if (flags & FLAGS_LEFTADJUST)
 2575:     {
 2576:       while (width-- > 0)
 2577: 	self->OutStream(self, CHAR_ADJUST);
 2578:     }
 2579:   if (flags & FLAGS_QUOTE)
 2580:     self->OutStream(self, CHAR_QUOTE);
 2581: }
 2582: #endif /* TRIO_WIDECHAR */
 2583: 
 2584: /*************************************************************************
 2585:  * TrioWriteDouble
 2586:  *
 2587:  * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm
 2588:  *
 2589:  * "5.2.4.2.2 paragraph #4
 2590:  *
 2591:  *  The accuracy [...] is implementation defined, as is the accuracy
 2592:  *  of the conversion between floating-point internal representations
 2593:  *  and string representations performed by the libray routine in
 2594:  *  <stdio.h>"
 2595:  */
 2596: /* FIXME: handle all instances of constant long-double number (L)
 2597:  *   and *l() math functions.
 2598:  */
 2599: TRIO_PRIVATE void
 2600: TrioWriteDouble
 2601: TRIO_ARGS6((self, number, flags, width, precision, base),
 2602: 	   trio_class_t *self,
 2603: 	   trio_long_double_t number,
 2604: 	   trio_flags_t flags,
 2605: 	   int width,
 2606: 	   int precision,
 2607: 	   int base)
 2608: {
 2609:   trio_long_double_t integerNumber;
 2610:   trio_long_double_t fractionNumber;
 2611:   trio_long_double_t workNumber;
 2612:   int integerDigits;
 2613:   int fractionDigits;
 2614:   int exponentDigits;
 2615:   int baseDigits;
 2616:   int integerThreshold;
 2617:   int fractionThreshold;
 2618:   int expectedWidth;
 2619:   int exponent = 0;
 2620:   unsigned int uExponent = 0;
 2621:   int exponentBase;
 2622:   trio_long_double_t dblBase;
 2623:   trio_long_double_t dblIntegerBase;
 2624:   trio_long_double_t dblFractionBase;
 2625:   trio_long_double_t integerAdjust;
 2626:   trio_long_double_t fractionAdjust;
 2627:   BOOLEAN_T isNegative;
 2628:   BOOLEAN_T isExponentNegative = FALSE;
 2629:   BOOLEAN_T requireTwoDigitExponent;
 2630:   BOOLEAN_T isHex;
 2631:   TRIO_CONST char *digits;
 2632:   char *groupingPointer;
 2633:   int i;
 2634:   int index;
 2635:   BOOLEAN_T hasOnlyZeroes;
 2636:   int zeroes = 0;
 2637:   register int trailingZeroes;
 2638:   BOOLEAN_T keepTrailingZeroes;
 2639:   BOOLEAN_T keepDecimalPoint;
 2640:   trio_long_double_t epsilon;
 2641:   
 2642:   assert(VALID(self));
 2643:   assert(VALID(self->OutStream));
 2644:   assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
 2645: 
 2646:   /* Determine sign and look for special quantities */
 2647:   switch (trio_fpclassify_and_signbit(number, &isNegative))
 2648:     {
 2649:     case TRIO_FP_NAN:
 2650:       TrioWriteString(self,
 2651: 		      (flags & FLAGS_UPPER)
 2652: 		      ? NAN_UPPER
 2653: 		      : NAN_LOWER,
 2654: 		      flags, width, precision);
 2655:       return;
 2656:       
 2657:     case TRIO_FP_INFINITE:
 2658:       if (isNegative)
 2659: 	{
 2660: 	  /* Negative infinity */
 2661: 	  TrioWriteString(self,
 2662: 			  (flags & FLAGS_UPPER)
 2663: 			  ? "-" INFINITE_UPPER
 2664: 			  : "-" INFINITE_LOWER,
 2665: 			  flags, width, precision);
 2666: 	  return;
 2667: 	}
 2668:       else
 2669: 	{
 2670: 	  /* Positive infinity */
 2671: 	  TrioWriteString(self,
 2672: 			  (flags & FLAGS_UPPER)
 2673: 			  ? INFINITE_UPPER
 2674: 			  : INFINITE_LOWER,
 2675: 			  flags, width, precision);
 2676: 	  return;
 2677: 	}
 2678: 
 2679:     default:
 2680:       /* Finitude */
 2681:       break;
 2682:     }
 2683:   
 2684:   /* Normal numbers */
 2685:   if (flags & FLAGS_LONGDOUBLE)
 2686:     {
 2687:       baseDigits = (base == 10)
 2688: 	? LDBL_DIG
 2689: 	: (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base));
 2690:       epsilon = LDBL_EPSILON;
 2691:     }
 2692:   else if (flags & FLAGS_SHORT)
 2693:     {
 2694:       baseDigits = (base == BASE_DECIMAL)
 2695: 	? FLT_DIG
 2696: 	: (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base));
 2697:       epsilon = FLT_EPSILON;
 2698:     }
 2699:   else
 2700:     {
 2701:       baseDigits = (base == BASE_DECIMAL)
 2702: 	? DBL_DIG
 2703: 	: (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base));
 2704:       epsilon = DBL_EPSILON;
 2705:     }
 2706: 
 2707:   digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
 2708:   isHex = (base == BASE_HEX);
 2709:   if (base == NO_BASE)
 2710:     base = BASE_DECIMAL;
 2711:   dblBase = (trio_long_double_t)base;
 2712:   keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) ||
 2713: 			  ( (flags & FLAGS_FLOAT_G) &&
 2714: 			    !(flags & FLAGS_ALTERNATIVE) ) );
 2715: 
 2716:   if (flags & FLAGS_ROUNDING)
 2717:     precision = baseDigits;
 2718: 
 2719:   if (precision == NO_PRECISION)
 2720:     {
 2721:       if (isHex)
 2722: 	{
 2723: 	  keepTrailingZeroes = FALSE;
 2724: 	  precision = FLT_MANT_DIG;
 2725: 	}
 2726:       else
 2727: 	{
 2728: 	  precision = FLT_DIG;
 2729: 	}
 2730:     }
 2731:   
 2732:   if (isNegative)
 2733:     number = -number;
 2734: 
 2735:   if (isHex)
 2736:     flags |= FLAGS_FLOAT_E;
 2737:   
 2738:   if (flags & FLAGS_FLOAT_G)
 2739:     {
 2740:       if (precision == 0)
 2741: 	precision = 1;
 2742: 
 2743:       if ((number < 1.0E-4) || (number > powl(base,
 2744: 					      (trio_long_double_t)precision)))
 2745: 	{
 2746: 	  /* Use scientific notation */
 2747: 	  flags |= FLAGS_FLOAT_E;
 2748: 	}
 2749:       else if (number < 1.0)
 2750: 	{
 2751: 	  /*
 2752: 	   * Use normal notation. If the integer part of the number is
 2753: 	   * zero, then adjust the precision to include leading fractional
 2754: 	   * zeros.
 2755: 	   */
 2756: 	  workNumber = TrioLogarithm(number, base);
 2757: 	  workNumber = TRIO_FABS(workNumber);
 2758: 	  if (workNumber - floorl(workNumber) < 0.001)
 2759: 	    workNumber--;
 2760: 	  zeroes = (int)floorl(workNumber);
 2761: 	}
 2762:     }
 2763: 
 2764:   if (flags & FLAGS_FLOAT_E)
 2765:     {
 2766:       /* Scale the number */
 2767:       workNumber = TrioLogarithm(number, base);
 2768:       if (trio_isinf(workNumber) == -1)
 2769: 	{
 2770: 	  exponent = 0;
 2771: 	  /* Undo setting */
 2772: 	  if (flags & FLAGS_FLOAT_G)
 2773: 	    flags &= ~FLAGS_FLOAT_E;
 2774: 	}
 2775:       else
 2776: 	{
 2777: 	  exponent = (int)floorl(workNumber);
 2778: 	  number /= powl(dblBase, (trio_long_double_t)exponent);
 2779: 	  isExponentNegative = (exponent < 0);
 2780: 	  uExponent = (isExponentNegative) ? -exponent : exponent;
 2781: 	  if (isHex)
 2782: 	    uExponent *= 4; /* log16(2) */
 2783: 	  /* No thousand separators */
 2784: 	  flags &= ~FLAGS_QUOTE;
 2785: 	}
 2786:     }
 2787: 
 2788:   integerNumber = floorl(number);
 2789:   fractionNumber = number - integerNumber;
 2790:   
 2791:   /*
 2792:    * Truncated number.
 2793:    *
 2794:    * Precision is number of significant digits for FLOAT_G
 2795:    * and number of fractional digits for others.
 2796:    */
 2797:   integerDigits = (integerNumber > epsilon)
 2798:     ? 1 + (int)TrioLogarithm(integerNumber, base)
 2799:     : 1;
 2800:   fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
 2801:     ? precision - integerDigits
 2802:     : zeroes + precision;
 2803: 
 2804:   dblFractionBase = TrioPower(base, fractionDigits);
 2805:   
 2806:   workNumber = number + 0.5 / dblFractionBase;
 2807:   if (floorl(number) != floorl(workNumber))
 2808:     {
 2809:       if (flags & FLAGS_FLOAT_E)
 2810: 	{
 2811: 	  /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
 2812: 	  exponent++;
 2813: 	  isExponentNegative = (exponent < 0);
 2814: 	  uExponent = (isExponentNegative) ? -exponent : exponent;
 2815: 	  if (isHex)
 2816: 	    uExponent *= 4; /* log16(2) */
 2817: 	  workNumber = (number + 0.5 / dblFractionBase) / dblBase;
 2818: 	  integerNumber = floorl(workNumber);
 2819: 	  fractionNumber = workNumber - integerNumber;
 2820: 	}
 2821:       else
 2822: 	{
 2823: 	  /* Adjust if number was rounded up one digit (ie. 99 to 100) */
 2824: 	  integerNumber = floorl(number + 0.5);
 2825: 	  fractionNumber = 0.0;
 2826: 	  integerDigits = (integerNumber > epsilon)
 2827: 	    ? 1 + (int)TrioLogarithm(integerNumber, base)
 2828: 	    : 1;
 2829: 	}
 2830:     }
 2831: 
 2832:   /* Estimate accuracy */
 2833:   integerAdjust = fractionAdjust = 0.5;
 2834:   if (flags & FLAGS_ROUNDING)
 2835:     {
 2836:       if (integerDigits > baseDigits)
 2837: 	{
 2838: 	  integerThreshold = baseDigits;
 2839: 	  fractionDigits = 0;
 2840: 	  dblFractionBase = 1.0;
 2841: 	  fractionThreshold = 0;
 2842: 	  precision = 0; /* Disable decimal-point */
 2843: 	  integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1);
 2844: 	  fractionAdjust = 0.0;
 2845: 	}
 2846:       else
 2847: 	{
 2848: 	  integerThreshold = integerDigits;
 2849: 	  fractionThreshold = fractionDigits - integerThreshold;
 2850: 	  fractionAdjust = 1.0;
 2851: 	}
 2852:     }
 2853:   else
 2854:     {
 2855:       integerThreshold = INT_MAX;
 2856:       fractionThreshold = INT_MAX;
 2857:     }
 2858:   
 2859:   /*
 2860:    * Calculate expected width.
 2861:    *  sign + integer part + thousands separators + decimal point
 2862:    *  + fraction + exponent
 2863:    */
 2864:   fractionAdjust /= dblFractionBase;
 2865:   hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon);
 2866:   keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) ||
 2867: 		       !((precision == 0) ||
 2868: 			 (!keepTrailingZeroes && hasOnlyZeroes)) );
 2869:   if (flags & FLAGS_FLOAT_E)
 2870:     {
 2871:       exponentDigits = (uExponent == 0)
 2872: 	? 1
 2873: 	: (int)ceil(TrioLogarithm((double)(uExponent + 1),
 2874: 				  (isHex) ? 10.0 : base));
 2875:     }
 2876:   else
 2877:     exponentDigits = 0;
 2878:   requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1));
 2879: 
 2880:   expectedWidth = integerDigits + fractionDigits
 2881:     + (keepDecimalPoint
 2882:        ? internalDecimalPointLength
 2883:        : 0)
 2884:     + ((flags & FLAGS_QUOTE)
 2885:        ? TrioCalcThousandSeparatorLength(integerDigits)
 2886:        : 0);
 2887:   if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
 2888:     expectedWidth += sizeof("-") - 1;
 2889:   if (exponentDigits > 0)
 2890:     expectedWidth += exponentDigits +
 2891:       ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1);
 2892:   if (isHex)
 2893:     expectedWidth += sizeof("0X") - 1;
 2894:   
 2895:   /* Output prefixing */
 2896:   if (flags & FLAGS_NILPADDING)
 2897:     {
 2898:       /* Leading zeros must be after sign */
 2899:       if (isNegative)
 2900: 	self->OutStream(self, '-');
 2901:       else if (flags & FLAGS_SHOWSIGN)
 2902: 	self->OutStream(self, '+');
 2903:       else if (flags & FLAGS_SPACE)
 2904: 	self->OutStream(self, ' ');
 2905:       if (isHex)
 2906: 	{
 2907: 	  self->OutStream(self, '0');
 2908: 	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
 2909: 	}
 2910:       if (!(flags & FLAGS_LEFTADJUST))
 2911: 	{
 2912: 	  for (i = expectedWidth; i < width; i++)
 2913: 	    {
 2914: 	      self->OutStream(self, '0');
 2915: 	    }
 2916: 	}
 2917:     }
 2918:   else
 2919:     {
 2920:       /* Leading spaces must be before sign */
 2921:       if (!(flags & FLAGS_LEFTADJUST))
 2922: 	{
 2923: 	  for (i = expectedWidth; i < width; i++)
 2924: 	    {
 2925: 	      self->OutStream(self, CHAR_ADJUST);
 2926: 	    }
 2927: 	}
 2928:       if (isNegative)
 2929: 	self->OutStream(self, '-');
 2930:       else if (flags & FLAGS_SHOWSIGN)
 2931: 	self->OutStream(self, '+');
 2932:       else if (flags & FLAGS_SPACE)
 2933: 	self->OutStream(self, ' ');
 2934:       if (isHex)
 2935: 	{
 2936: 	  self->OutStream(self, '0');
 2937: 	  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
 2938: 	}
 2939:     }
 2940:   
 2941:   /* Output the integer part and thousand separators */
 2942:   dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1);
 2943:   for (i = 0; i < integerDigits; i++)
 2944:     {
 2945:       workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase));
 2946:       if (i > integerThreshold)
 2947: 	{
 2948: 	  /* Beyond accuracy */
 2949: 	  self->OutStream(self, digits[0]);
 2950: 	}
 2951:       else
 2952: 	{
 2953: 	  self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]);
 2954: 	}
 2955:       dblIntegerBase *= dblBase;
 2956:       
 2957:       if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
 2958: 	  && TrioFollowedBySeparator(integerDigits - i))
 2959: 	{
 2960: 	  for (groupingPointer = internalThousandSeparator;
 2961: 	       *groupingPointer != NIL;
 2962: 	       groupingPointer++)
 2963: 	    {
 2964: 	      self->OutStream(self, *groupingPointer);
 2965: 	    }
 2966: 	}
 2967:     }
 2968:   
 2969:   /* Insert decimal point and build the fraction part */
 2970:   trailingZeroes = 0;
 2971: 
 2972:   if (keepDecimalPoint)
 2973:     {
 2974:       if (internalDecimalPoint)
 2975: 	{
 2976: 	  self->OutStream(self, internalDecimalPoint);
 2977: 	}
 2978:       else
 2979: 	{
 2980: 	  for (i = 0; i < internalDecimalPointLength; i++)
 2981: 	    {
 2982: 	      self->OutStream(self, internalDecimalPointString[i]);
 2983: 	    }
 2984: 	}
 2985:     }
 2986: 
 2987:   for (i = 0; i < fractionDigits; i++)
 2988:     {
 2989:       if ((integerDigits > integerThreshold) || (i > fractionThreshold))
 2990: 	{
 2991: 	  /* Beyond accuracy */
 2992: 	  trailingZeroes++;
 2993: 	}
 2994:       else
 2995: 	{
 2996: 	  fractionNumber *= dblBase;
 2997: 	  fractionAdjust *= dblBase;
 2998: 	  workNumber = floorl(fractionNumber + fractionAdjust);
 2999: 	  fractionNumber -= workNumber;
 3000: 	  index = (int)fmodl(workNumber, dblBase);
 3001: 	  if (index == 0)
 3002: 	    {
 3003: 	      trailingZeroes++;
 3004: 	    }
 3005: 	  else
 3006: 	    {
 3007: 	      while (trailingZeroes > 0)
 3008: 		{
 3009: 		  /* Not trailing zeroes after all */
 3010: 		  self->OutStream(self, digits[0]);
 3011: 		  trailingZeroes--;
 3012: 		}
 3013: 	      self->OutStream(self, digits[index]);
 3014: 	    }
 3015: 	}
 3016:     }
 3017:   
 3018:   if (keepTrailingZeroes)
 3019:     {
 3020:       while (trailingZeroes > 0)
 3021: 	{
 3022: 	  self->OutStream(self, digits[0]);
 3023: 	  trailingZeroes--;
 3024: 	}
 3025:     }
 3026:   
 3027:   /* Output exponent */
 3028:   if (exponentDigits > 0)
 3029:     {
 3030:       self->OutStream(self,
 3031: 		      isHex
 3032: 		      ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
 3033: 		      : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
 3034:       self->OutStream(self, (isExponentNegative) ? '-' : '+');
 3035: 
 3036:       /* The exponent must contain at least two digits */
 3037:       if (requireTwoDigitExponent)
 3038:         self->OutStream(self, '0');
 3039: 
 3040:       if (isHex)
 3041: 	base = 10.0;
 3042:       exponentBase = (int)TrioPower(base, exponentDigits - 1);
 3043:       for (i = 0; i < exponentDigits; i++)
 3044: 	{
 3045: 	  self->OutStream(self, digits[(uExponent / exponentBase) % base]);
 3046: 	  exponentBase /= base;
 3047: 	}
 3048:     }
 3049:   /* Output trailing spaces */
 3050:   if (flags & FLAGS_LEFTADJUST)
 3051:     {
 3052:       for (i = expectedWidth; i < width; i++)
 3053: 	{
 3054: 	  self->OutStream(self, CHAR_ADJUST);
 3055: 	}
 3056:     }
 3057: }
 3058: 
 3059: /*************************************************************************
 3060:  * TrioFormatProcess
 3061:  *
 3062:  * Description:
 3063:  *  This is the main engine for formatting output
 3064:  */
 3065: TRIO_PRIVATE int
 3066: TrioFormatProcess
 3067: TRIO_ARGS3((data, format, parameters),
 3068: 	   trio_class_t *data,
 3069: 	   TRIO_CONST char *format,
 3070: 	   trio_parameter_t *parameters)
 3071: {
 3072: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 3073:   int charlen;
 3074: #endif
 3075:   int i;
 3076:   TRIO_CONST char *string;
 3077:   trio_pointer_t pointer;
 3078:   trio_flags_t flags;
 3079:   int width;
 3080:   int precision;
 3081:   int base;
 3082:   int index;
 3083:   
 3084:   index = 0;
 3085:   i = 0;
 3086: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 3087:   (void)mblen(NULL, 0);
 3088: #endif
 3089:   
 3090:   while (format[index])
 3091:     {
 3092: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 3093:       if (! isascii(format[index]))
 3094: 	{
 3095: 	  charlen = mblen(&format[index], MB_LEN_MAX);
 3096: 	  /*
 3097: 	   * Only valid multibyte characters are handled here. Invalid
 3098: 	   * multibyte characters (charlen == -1) are handled as normal
 3099: 	   * characters.
 3100: 	   */
 3101: 	  if (charlen != -1)
 3102: 	    {
 3103: 	      while (charlen-- > 0)
 3104: 		{
 3105: 		  data->OutStream(data, format[index++]);
 3106: 		}
 3107: 	      continue; /* while characters left in formatting string */
 3108: 	    }
 3109: 	}
 3110: #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
 3111:       if (CHAR_IDENTIFIER == format[index])
 3112: 	{
 3113: 	  if (CHAR_IDENTIFIER == format[index + 1])
 3114: 	    {
 3115: 	      data->OutStream(data, CHAR_IDENTIFIER);
 3116: 	      index += 2;
 3117: 	    }
 3118: 	  else
 3119: 	    {
 3120: 	      /* Skip the parameter entries */
 3121: 	      while (parameters[i].type == FORMAT_PARAMETER)
 3122: 		i++;
 3123: 	      
 3124: 	      flags = parameters[i].flags;
 3125: 
 3126: 	      /* Find width */
 3127: 	      width = parameters[i].width;
 3128: 	      if (flags & FLAGS_WIDTH_PARAMETER)
 3129: 		{
 3130: 		  /* Get width from parameter list */
 3131: 		  width = (int)parameters[width].data.number.as_signed;
 3132: 		  if (width < 0)
 3133: 		    {
 3134: 		      /*
 3135: 		       * A negative width is the same as the - flag and
 3136: 		       * a positive width.
 3137: 		       */
 3138: 		      flags |= FLAGS_LEFTADJUST;
 3139: 		      flags &= ~FLAGS_NILPADDING;
 3140: 		      width = -width;
 3141: 		    }
 3142: 		}
 3143: 	      
 3144: 	      /* Find precision */
 3145: 	      if (flags & FLAGS_PRECISION)
 3146: 		{
 3147: 		  precision = parameters[i].precision;
 3148: 		  if (flags & FLAGS_PRECISION_PARAMETER)
 3149: 		    {
 3150: 		      /* Get precision from parameter list */
 3151: 		      precision = (int)parameters[precision].data.number.as_signed;
 3152: 		      if (precision < 0)
 3153: 			{
 3154: 			  /*
 3155: 			   * A negative precision is the same as no
 3156: 			   * precision
 3157: 			   */
 3158: 			  precision = NO_PRECISION;
 3159: 			}
 3160: 		    }
 3161: 		}
 3162: 	      else
 3163: 		{
 3164: 		  precision = NO_PRECISION;
 3165: 		}
 3166: 
 3167: 	      /* Find base */
 3168: 	      base = parameters[i].base;
 3169: 	      if (flags & FLAGS_BASE_PARAMETER)
 3170: 		{
 3171: 		  /* Get base from parameter list */
 3172: 		  base = (int)parameters[base].data.number.as_signed;
 3173: 		}
 3174: 	      
 3175: 	      switch (parameters[i].type)
 3176: 		{
 3177: 		case FORMAT_CHAR:
 3178: 		  if (flags & FLAGS_QUOTE)
 3179: 		    data->OutStream(data, CHAR_QUOTE);
 3180: 		  if (! (flags & FLAGS_LEFTADJUST))
 3181: 		    {
 3182: 		      while (--width > 0)
 3183: 			data->OutStream(data, CHAR_ADJUST);
 3184: 		    }
 3185: #if TRIO_WIDECHAR
 3186: 		  if (flags & FLAGS_WIDECHAR)
 3187: 		    {
 3188: 		      TrioWriteWideStringCharacter(data,
 3189: 						   (trio_wchar_t)parameters[i].data.number.as_signed,
 3190: 						   flags,
 3191: 						   NO_WIDTH);
 3192: 		    }
 3193: 		  else
 3194: #endif
 3195: 		    {
 3196: 		      TrioWriteStringCharacter(data,
 3197: 					       (int)parameters[i].data.number.as_signed,
 3198: 					       flags);
 3199: 		    }
 3200: 
 3201: 		  if (flags & FLAGS_LEFTADJUST)
 3202: 		    {
 3203: 		      while(--width > 0)
 3204: 			data->OutStream(data, CHAR_ADJUST);
 3205: 		    }
 3206: 		  if (flags & FLAGS_QUOTE)
 3207: 		    data->OutStream(data, CHAR_QUOTE);
 3208: 
 3209: 		  break; /* FORMAT_CHAR */
 3210: 
 3211: 		case FORMAT_INT:
 3212: 		  TrioWriteNumber(data,
 3213: 				  parameters[i].data.number.as_unsigned,
 3214: 				  flags,
 3215: 				  width,
 3216: 				  precision,
 3217: 				  base);
 3218: 
 3219: 		  break; /* FORMAT_INT */
 3220: 
 3221: 		case FORMAT_DOUBLE:
 3222: 		  TrioWriteDouble(data,
 3223: 				  parameters[i].data.longdoubleNumber,
 3224: 				  flags,
 3225: 				  width,
 3226: 				  precision,
 3227: 				  base);
 3228: 		  break; /* FORMAT_DOUBLE */
 3229: 
 3230: 		case FORMAT_STRING:
 3231: #if TRIO_WIDECHAR
 3232: 		  if (flags & FLAGS_WIDECHAR)
 3233: 		    {
 3234: 		      TrioWriteWideString(data,
 3235: 					  parameters[i].data.wstring,
 3236: 					  flags,
 3237: 					  width,
 3238: 					  precision);
 3239: 		    }
 3240: 		  else
 3241: #endif
 3242: 		    {
 3243: 		      TrioWriteString(data,
 3244: 				      parameters[i].data.string,
 3245: 				      flags,
 3246: 				      width,
 3247: 				      precision);
 3248: 		    }
 3249: 		  break; /* FORMAT_STRING */
 3250: 
 3251: 		case FORMAT_POINTER:
 3252: 		  {
 3253: 		    trio_reference_t reference;
 3254: 		    
 3255: 		    reference.data = data;
 3256: 		    reference.parameter = &parameters[i];
 3257: 		    trio_print_pointer(&reference, parameters[i].data.pointer);
 3258: 		  }
 3259: 		  break; /* FORMAT_POINTER */
 3260: 
 3261: 		case FORMAT_COUNT:
 3262: 		  pointer = parameters[i].data.pointer;
 3263: 		  if (NULL != pointer)
 3264: 		    {
 3265: 		      /*
 3266: 		       * C99 paragraph 7.19.6.1.8 says "the number of
 3267: 		       * characters written to the output stream so far by
 3268: 		       * this call", which is data->committed
 3269: 		       */
 3270: #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
 3271: 		      if (flags & FLAGS_SIZE_T)
 3272: 			*(size_t *)pointer = (size_t)data->committed;
 3273: 		      else
 3274: #endif
 3275: #if defined(QUALIFIER_PTRDIFF_T)
 3276: 		      if (flags & FLAGS_PTRDIFF_T)
 3277: 			*(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
 3278: 		      else
 3279: #endif
 3280: #if defined(QUALIFIER_INTMAX_T)
 3281: 		      if (flags & FLAGS_INTMAX_T)
 3282: 			*(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
 3283: 		      else
 3284: #endif
 3285: 		      if (flags & FLAGS_QUAD)
 3286: 			{
 3287: 			  *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
 3288: 			}
 3289: 		      else if (flags & FLAGS_LONG)
 3290: 			{
 3291: 			  *(long int *)pointer = (long int)data->committed;
 3292: 			}
 3293: 		      else if (flags & FLAGS_SHORT)
 3294: 			{
 3295: 			  *(short int *)pointer = (short int)data->committed;
 3296: 			}
 3297: 		      else
 3298: 			{
 3299: 			  *(int *)pointer = (int)data->committed;
 3300: 			}
 3301: 		    }
 3302: 		  break; /* FORMAT_COUNT */
 3303: 
 3304: 		case FORMAT_PARAMETER:
 3305: 		  break; /* FORMAT_PARAMETER */
 3306: 
 3307: #if defined(FORMAT_ERRNO)
 3308: 		case FORMAT_ERRNO:
 3309: 		  string = trio_error(parameters[i].data.errorNumber);
 3310: 		  if (string)
 3311: 		    {
 3312: 		      TrioWriteString(data,
 3313: 				      string,
 3314: 				      flags,
 3315: 				      width,
 3316: 				      precision);
 3317: 		    }
 3318: 		  else
 3319: 		    {
 3320: 		      data->OutStream(data, '#');
 3321: 		      TrioWriteNumber(data,
 3322: 				      (trio_uintmax_t)parameters[i].data.errorNumber,
 3323: 				      flags,
 3324: 				      width,
 3325: 				      precision,
 3326: 				      BASE_DECIMAL);
 3327: 		    }
 3328: 		  break; /* FORMAT_ERRNO */
 3329: #endif /* defined(FORMAT_ERRNO) */
 3330: 
 3331: #if defined(FORMAT_USER_DEFINED)
 3332: 		case FORMAT_USER_DEFINED:
 3333: 		  {
 3334: 		    trio_reference_t reference;
 3335: 		    trio_userdef_t *def = NULL;
 3336: 
 3337: 		    if (parameters[i].user_name[0] == NIL)
 3338: 		      {
 3339: 			/* Use handle */
 3340: 			if ((i > 0) ||
 3341: 			    (parameters[i - 1].type == FORMAT_PARAMETER))
 3342: 			  def = (trio_userdef_t *)parameters[i - 1].data.pointer;
 3343: 		      }
 3344: 		    else
 3345: 		      {
 3346: 			/* Look up namespace */
 3347: 			def = TrioFindNamespace(parameters[i].user_name, NULL);
 3348: 		      }
 3349: 		    if (def) {
 3350: 		      reference.data = data;
 3351: 		      reference.parameter = &parameters[i];
 3352: 		      def->callback(&reference);
 3353: 		    }
 3354: 		  }
 3355: 		  break;
 3356: #endif /* defined(FORMAT_USER_DEFINED) */
 3357: 		  
 3358: 		default:
 3359: 		  break;
 3360: 		} /* switch parameter type */
 3361: 
 3362: 	      /* Prepare for next */
 3363: 	      index = parameters[i].indexAfterSpecifier;
 3364: 	      i++;
 3365: 	    }
 3366: 	}
 3367:       else /* not identifier */
 3368: 	{
 3369: 	  data->OutStream(data, format[index++]);
 3370: 	}
 3371:     }
 3372:   return data->processed;
 3373: }
 3374: 
 3375: /*************************************************************************
 3376:  * TrioFormatRef
 3377:  */
 3378: TRIO_PRIVATE int
 3379: TrioFormatRef
 3380: TRIO_ARGS4((reference, format, arglist, argarray),
 3381: 	   trio_reference_t *reference,
 3382: 	   TRIO_CONST char *format,
 3383: 	   va_list *arglist,
 3384: 	   trio_pointer_t *argarray)
 3385: {
 3386:   int status;
 3387:   trio_parameter_t parameters[MAX_PARAMETERS];
 3388: 
 3389:   status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
 3390:   if (status < 0)
 3391:     return status;
 3392: 
 3393:   status = TrioFormatProcess(reference->data, format, parameters);
 3394:   if (reference->data->error != 0)
 3395:     {
 3396:       status = reference->data->error;
 3397:     }
 3398:   return status;
 3399: }
 3400: 
 3401: /*************************************************************************
 3402:  * TrioFormat
 3403:  */
 3404: TRIO_PRIVATE int
 3405: TrioFormat
 3406: TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
 3407: 	   trio_pointer_t destination,
 3408: 	   size_t destinationSize,
 3409: 	   void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
 3410: 	   TRIO_CONST char *format,
 3411: 	   va_list *arglist,
 3412: 	   trio_pointer_t *argarray)
 3413: {
 3414:   int status;
 3415:   trio_class_t data;
 3416:   trio_parameter_t parameters[MAX_PARAMETERS];
 3417: 
 3418:   assert(VALID(OutStream));
 3419:   assert(VALID(format));
 3420: 
 3421:   memset(&data, 0, sizeof(data));
 3422:   data.OutStream = OutStream;
 3423:   data.location = destination;
 3424:   data.max = destinationSize;
 3425:   data.error = 0;
 3426: 
 3427: #if defined(USE_LOCALE)
 3428:   if (NULL == internalLocaleValues)
 3429:     {
 3430:       TrioSetLocale();
 3431:     }
 3432: #endif
 3433: 
 3434:   status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
 3435:   if (status < 0)
 3436:     return status;
 3437: 
 3438:   status = TrioFormatProcess(&data, format, parameters);
 3439:   if (data.error != 0)
 3440:     {
 3441:       status = data.error;
 3442:     }
 3443:   return status;
 3444: }
 3445: 
 3446: /*************************************************************************
 3447:  * TrioOutStreamFile
 3448:  */
 3449: TRIO_PRIVATE void
 3450: TrioOutStreamFile
 3451: TRIO_ARGS2((self, output),
 3452: 	   trio_class_t *self,
 3453: 	   int output)
 3454: {
 3455:   FILE *file;
 3456: 
 3457:   assert(VALID(self));
 3458:   assert(VALID(self->location));
 3459: 
 3460:   file = (FILE *)self->location;
 3461:   self->processed++;
 3462:   if (fputc(output, file) == EOF)
 3463:     {
 3464:       self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
 3465:     }
 3466:   else
 3467:     {
 3468:       self->committed++;
 3469:     }
 3470: }
 3471: 
 3472: /*************************************************************************
 3473:  * TrioOutStreamFileDescriptor
 3474:  */
 3475: TRIO_PRIVATE void
 3476: TrioOutStreamFileDescriptor
 3477: TRIO_ARGS2((self, output),
 3478: 	   trio_class_t *self,
 3479: 	   int output)
 3480: {
 3481:   int fd;
 3482:   char ch;
 3483: 
 3484:   assert(VALID(self));
 3485: 
 3486:   fd = *((int *)self->location);
 3487:   ch = (char)output;
 3488:   self->processed++;
 3489:   if (write(fd, &ch, sizeof(char)) == -1)
 3490:     {
 3491:       self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
 3492:     }
 3493:   else
 3494:     {
 3495:       self->committed++;
 3496:     }
 3497: }
 3498: 
 3499: /*************************************************************************
 3500:  * TrioOutStreamCustom
 3501:  */
 3502: TRIO_PRIVATE void
 3503: TrioOutStreamCustom
 3504: TRIO_ARGS2((self, output),
 3505: 	   trio_class_t *self,
 3506: 	   int output)
 3507: {
 3508:   int status;
 3509:   trio_custom_t *data;
 3510: 
 3511:   assert(VALID(self));
 3512:   assert(VALID(self->location));
 3513: 
 3514:   data = (trio_custom_t *)self->location;
 3515:   if (data->stream.out)
 3516:     {
 3517:       status = (data->stream.out)(data->closure, output);
 3518:       if (status >= 0)
 3519: 	{
 3520: 	  self->committed++;
 3521: 	}
 3522:       else
 3523: 	{
 3524: 	  if (self->error == 0)
 3525: 	    {
 3526: 	      self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status);
 3527: 	    }
 3528: 	}
 3529:     }
 3530:   self->processed++;
 3531: }
 3532: 
 3533: /*************************************************************************
 3534:  * TrioOutStreamString
 3535:  */
 3536: TRIO_PRIVATE void
 3537: TrioOutStreamString
 3538: TRIO_ARGS2((self, output),
 3539: 	   trio_class_t *self,
 3540: 	   int output)
 3541: {
 3542:   char **buffer;
 3543: 
 3544:   assert(VALID(self));
 3545:   assert(VALID(self->location));
 3546: 
 3547:   buffer = (char **)self->location;
 3548:   **buffer = (char)output;
 3549:   (*buffer)++;
 3550:   self->processed++;
 3551:   self->committed++;
 3552: }
 3553: 
 3554: /*************************************************************************
 3555:  * TrioOutStreamStringMax
 3556:  */
 3557: TRIO_PRIVATE void
 3558: TrioOutStreamStringMax
 3559: TRIO_ARGS2((self, output),
 3560: 	   trio_class_t *self,
 3561: 	   int output)
 3562: {
 3563:   char **buffer;
 3564: 
 3565:   assert(VALID(self));
 3566:   assert(VALID(self->location));
 3567:   
 3568:   buffer = (char **)self->location;
 3569: 
 3570:   if (self->processed < self->max)
 3571:     {
 3572:       **buffer = (char)output;
 3573:       (*buffer)++;
 3574:       self->committed++;
 3575:     }
 3576:   self->processed++;
 3577: }
 3578: 
 3579: /*************************************************************************
 3580:  * TrioOutStreamStringDynamic
 3581:  */
 3582: TRIO_PRIVATE void
 3583: TrioOutStreamStringDynamic
 3584: TRIO_ARGS2((self, output),
 3585: 	   trio_class_t *self,
 3586: 	   int output)
 3587: {
 3588:   assert(VALID(self));
 3589:   assert(VALID(self->location));
 3590: 
 3591:   if (self->error == 0)
 3592:     {
 3593:       trio_xstring_append_char((trio_string_t *)self->location,
 3594: 			       (char)output);
 3595:       self->committed++;
 3596:     }
 3597:   /* The processed variable must always be increased */
 3598:   self->processed++;
 3599: }
 3600: 
 3601: /*************************************************************************
 3602:  *
 3603:  * Formatted printing functions
 3604:  *
 3605:  ************************************************************************/
 3606: 
 3607: #if defined(TRIO_DOCUMENTATION)
 3608: # include "doc/doc_printf.h"
 3609: #endif
 3610: /** @addtogroup Printf
 3611:     @{
 3612: */
 3613: 
 3614: /*************************************************************************
 3615:  * printf
 3616:  */
 3617: 
 3618: /**
 3619:    Print to standard output stream.
 3620: 
 3621:    @param format Formatting string.
 3622:    @param ... Arguments.
 3623:    @return Number of printed characters.
 3624:  */
 3625: TRIO_PUBLIC int
 3626: trio_printf
 3627: TRIO_VARGS2((format, va_alist),
 3628: 	    TRIO_CONST char *format,
 3629: 	    TRIO_VA_DECL)
 3630: {
 3631:   int status;
 3632:   va_list args;
 3633: 
 3634:   assert(VALID(format));
 3635:   
 3636:   TRIO_VA_START(args, format);
 3637:   status = TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
 3638:   TRIO_VA_END(args);
 3639:   return status;
 3640: }
 3641: 
 3642: /**
 3643:    Print to standard output stream.
 3644: 
 3645:    @param format Formatting string.
 3646:    @param args Arguments.
 3647:    @return Number of printed characters.
 3648:  */
 3649: TRIO_PUBLIC int
 3650: trio_vprintf
 3651: TRIO_ARGS2((format, args),
 3652: 	   TRIO_CONST char *format,
 3653: 	   va_list args)
 3654: {
 3655:   assert(VALID(format));
 3656: 
 3657:   return TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
 3658: }
 3659: 
 3660: /**
 3661:    Print to standard output stream.
 3662: 
 3663:    @param format Formatting string.
 3664:    @param args Arguments.
 3665:    @return Number of printed characters.
 3666:  */
 3667: TRIO_PUBLIC int
 3668: trio_printfv
 3669: TRIO_ARGS2((format, args),
 3670: 	   TRIO_CONST char *format,
 3671: 	   trio_pointer_t * args)
 3672: {
 3673:   assert(VALID(format));
 3674: 
 3675:   return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
 3676: }
 3677: 
 3678: /*************************************************************************
 3679:  * fprintf
 3680:  */
 3681: 
 3682: /**
 3683:    Print to file.
 3684: 
 3685:    @param file File pointer.
 3686:    @param format Formatting string.
 3687:    @param ... Arguments.
 3688:    @return Number of printed characters.
 3689:  */
 3690: TRIO_PUBLIC int
 3691: trio_fprintf
 3692: TRIO_VARGS3((file, format, va_alist),
 3693: 	    FILE *file,
 3694: 	    TRIO_CONST char *format,
 3695: 	    TRIO_VA_DECL)
 3696: {
 3697:   int status;
 3698:   va_list args;
 3699: 
 3700:   assert(VALID(file));
 3701:   assert(VALID(format));
 3702:   
 3703:   TRIO_VA_START(args, format);
 3704:   status = TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
 3705:   TRIO_VA_END(args);
 3706:   return status;
 3707: }
 3708: 
 3709: /**
 3710:    Print to file.
 3711: 
 3712:    @param file File pointer.
 3713:    @param format Formatting string.
 3714:    @param args Arguments.
 3715:    @return Number of printed characters.
 3716:  */
 3717: TRIO_PUBLIC int
 3718: trio_vfprintf
 3719: TRIO_ARGS3((file, format, args),
 3720: 	   FILE *file,
 3721: 	   TRIO_CONST char *format,
 3722: 	   va_list args)
 3723: {
 3724:   assert(VALID(file));
 3725:   assert(VALID(format));
 3726:   
 3727:   return TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
 3728: }
 3729: 
 3730: /**
 3731:    Print to file.
 3732: 
 3733:    @param file File pointer.
 3734:    @param format Formatting string.
 3735:    @param args Arguments.
 3736:    @return Number of printed characters.
 3737:  */
 3738: TRIO_PUBLIC int
 3739: trio_fprintfv
 3740: TRIO_ARGS3((file, format, args),
 3741: 	   FILE *file,
 3742: 	   TRIO_CONST char *format,
 3743: 	   trio_pointer_t * args)
 3744: {
 3745:   assert(VALID(file));
 3746:   assert(VALID(format));
 3747:   
 3748:   return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
 3749: }
 3750: 
 3751: /*************************************************************************
 3752:  * dprintf
 3753:  */
 3754: 
 3755: /**
 3756:    Print to file descriptor.
 3757: 
 3758:    @param fd File descriptor.
 3759:    @param format Formatting string.
 3760:    @param ... Arguments.
 3761:    @return Number of printed characters.
 3762:  */
 3763: TRIO_PUBLIC int
 3764: trio_dprintf
 3765: TRIO_VARGS3((fd, format, va_alist),
 3766: 	    int fd,
 3767: 	    TRIO_CONST char *format,
 3768: 	    TRIO_VA_DECL)
 3769: {
 3770:   int status;
 3771:   va_list args;
 3772: 
 3773:   assert(VALID(format));
 3774:   
 3775:   TRIO_VA_START(args, format);
 3776:   status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
 3777:   TRIO_VA_END(args);
 3778:   return status;
 3779: }
 3780: 
 3781: /**
 3782:    Print to file descriptor.
 3783: 
 3784:    @param fd File descriptor.
 3785:    @param format Formatting string.
 3786:    @param args Arguments.
 3787:    @return Number of printed characters.
 3788:  */
 3789: TRIO_PUBLIC int
 3790: trio_vdprintf
 3791: TRIO_ARGS3((fd, format, args),
 3792: 	   int fd,
 3793: 	   TRIO_CONST char *format,
 3794: 	   va_list args)
 3795: {
 3796:   assert(VALID(format));
 3797:   
 3798:   return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
 3799: }
 3800: 
 3801: /**
 3802:    Print to file descriptor.
 3803: 
 3804:    @param fd File descriptor.
 3805:    @param format Formatting string.
 3806:    @param args Arguments.
 3807:    @return Number of printed characters.
 3808:  */
 3809: TRIO_PUBLIC int
 3810: trio_dprintfv
 3811: TRIO_ARGS3((fd, format, args),
 3812: 	   int fd,
 3813: 	   TRIO_CONST char *format,
 3814: 	   trio_pointer_t *args)
 3815: {
 3816:   assert(VALID(format));
 3817:   
 3818:   return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
 3819: }
 3820: 
 3821: /*************************************************************************
 3822:  * cprintf
 3823:  */
 3824: TRIO_PUBLIC int
 3825: trio_cprintf
 3826: TRIO_VARGS4((stream, closure, format, va_alist),
 3827: 	    trio_outstream_t stream,
 3828: 	    trio_pointer_t closure,
 3829: 	    TRIO_CONST char *format,
 3830: 	    TRIO_VA_DECL)
 3831: {
 3832:   int status;
 3833:   va_list args;
 3834:   trio_custom_t data;
 3835: 
 3836:   assert(VALID(stream));
 3837:   assert(VALID(format));
 3838: 
 3839:   TRIO_VA_START(args, format);
 3840:   data.stream.out = stream;
 3841:   data.closure = closure;
 3842:   status = TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
 3843:   TRIO_VA_END(args);
 3844:   return status;
 3845: }
 3846: 
 3847: TRIO_PUBLIC int
 3848: trio_vcprintf
 3849: TRIO_ARGS4((stream, closure, format, args),
 3850: 	   trio_outstream_t stream,
 3851: 	   trio_pointer_t closure,
 3852: 	   TRIO_CONST char *format,
 3853: 	   va_list args)
 3854: {
 3855:   trio_custom_t data;
 3856: 
 3857:   assert(VALID(stream));
 3858:   assert(VALID(format));
 3859: 
 3860:   data.stream.out = stream;
 3861:   data.closure = closure;
 3862:   return TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
 3863: }
 3864: 
 3865: TRIO_PUBLIC int
 3866: trio_cprintfv
 3867: TRIO_ARGS4((stream, closure, format, args),
 3868: 	   trio_outstream_t stream,
 3869: 	   trio_pointer_t closure,
 3870: 	   TRIO_CONST char *format,
 3871: 	   void **args)
 3872: {
 3873:   trio_custom_t data;
 3874: 
 3875:   assert(VALID(stream));
 3876:   assert(VALID(format));
 3877: 
 3878:   data.stream.out = stream;
 3879:   data.closure = closure;
 3880:   return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args);
 3881: }
 3882: 
 3883: /*************************************************************************
 3884:  * sprintf
 3885:  */
 3886: 
 3887: /**
 3888:    Print to string.
 3889: 
 3890:    @param buffer Output string.
 3891:    @param format Formatting string.
 3892:    @param ... Arguments.
 3893:    @return Number of printed characters.
 3894:  */
 3895: TRIO_PUBLIC int
 3896: trio_sprintf
 3897: TRIO_VARGS3((buffer, format, va_alist),
 3898: 	    char *buffer,
 3899: 	    TRIO_CONST char *format,
 3900: 	    TRIO_VA_DECL)
 3901: {
 3902:   int status;
 3903:   va_list args;
 3904: 
 3905:   assert(VALID(buffer));
 3906:   assert(VALID(format));
 3907:   
 3908:   TRIO_VA_START(args, format);
 3909:   status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
 3910:   *buffer = NIL; /* Terminate with NIL character */
 3911:   TRIO_VA_END(args);
 3912:   return status;
 3913: }
 3914: 
 3915: /**
 3916:    Print to string.
 3917: 
 3918:    @param buffer Output string.
 3919:    @param format Formatting string.
 3920:    @param args Arguments.
 3921:    @return Number of printed characters.
 3922:  */
 3923: TRIO_PUBLIC int
 3924: trio_vsprintf
 3925: TRIO_ARGS3((buffer, format, args),
 3926: 	   char *buffer,
 3927: 	   TRIO_CONST char *format,
 3928: 	   va_list args)
 3929: {
 3930:   int status;
 3931: 
 3932:   assert(VALID(buffer));
 3933:   assert(VALID(format));
 3934: 
 3935:   status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
 3936:   *buffer = NIL;
 3937:   return status;
 3938: }
 3939: 
 3940: /**
 3941:    Print to string.
 3942: 
 3943:    @param buffer Output string.
 3944:    @param format Formatting string.
 3945:    @param args Arguments.
 3946:    @return Number of printed characters.
 3947:  */
 3948: TRIO_PUBLIC int
 3949: trio_sprintfv
 3950: TRIO_ARGS3((buffer, format, args),
 3951: 	   char *buffer,
 3952: 	   TRIO_CONST char *format,
 3953: 	   trio_pointer_t *args)
 3954: {
 3955:   int status;
 3956: 
 3957:   assert(VALID(buffer));
 3958:   assert(VALID(format));
 3959: 
 3960:   status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
 3961:   *buffer = NIL;
 3962:   return status;
 3963: }
 3964: 
 3965: /*************************************************************************
 3966:  * snprintf
 3967:  */
 3968: 
 3969: /**
 3970:    Print at most @p max characters to string.
 3971: 
 3972:    @param buffer Output string.
 3973:    @param max Maximum number of characters to print.
 3974:    @param format Formatting string.
 3975:    @param ... Arguments.
 3976:    @return Number of printed characters.
 3977:  */
 3978: TRIO_PUBLIC int
 3979: trio_snprintf
 3980: TRIO_VARGS4((buffer, max, format, va_alist),
 3981: 	    char *buffer,
 3982: 	    size_t max,
 3983: 	    TRIO_CONST char *format,
 3984: 	    TRIO_VA_DECL)
 3985: {
 3986:   int status;
 3987:   va_list args;
 3988: 
 3989:   assert(VALID(buffer));
 3990:   assert(VALID(format));
 3991: 
 3992:   TRIO_VA_START(args, format);
 3993:   status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
 3994: 		      TrioOutStreamStringMax, format, &args, NULL);
 3995:   if (max > 0)
 3996:     *buffer = NIL;
 3997:   TRIO_VA_END(args);
 3998:   return status;
 3999: }
 4000: 
 4001: /**
 4002:    Print at most @p max characters to string.
 4003: 
 4004:    @param buffer Output string.
 4005:    @param max Maximum number of characters to print.
 4006:    @param format Formatting string.
 4007:    @param args Arguments.
 4008:    @return Number of printed characters.
 4009:  */
 4010: TRIO_PUBLIC int
 4011: trio_vsnprintf
 4012: TRIO_ARGS4((buffer, max, format, args),
 4013: 	   char *buffer,
 4014: 	   size_t max,
 4015: 	   TRIO_CONST char *format,
 4016: 	   va_list args)
 4017: {
 4018:   int status;
 4019: 
 4020:   assert(VALID(buffer));
 4021:   assert(VALID(format));
 4022: 
 4023:   status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
 4024: 		      TrioOutStreamStringMax, format, &args, NULL);
 4025:   if (max > 0)
 4026:     *buffer = NIL;
 4027:   return status;
 4028: }
 4029: 
 4030: /**
 4031:    Print at most @p max characters to string.
 4032: 
 4033:    @param buffer Output string.
 4034:    @param max Maximum number of characters to print.
 4035:    @param format Formatting string.
 4036:    @param args Arguments.
 4037:    @return Number of printed characters.
 4038:  */
 4039: TRIO_PUBLIC int
 4040: trio_snprintfv
 4041: TRIO_ARGS4((buffer, max, format, args),
 4042: 	   char *buffer,
 4043: 	   size_t max,
 4044: 	   TRIO_CONST char *format,
 4045: 	   trio_pointer_t *args)
 4046: {
 4047:   int status;
 4048: 
 4049:   assert(VALID(buffer));
 4050:   assert(VALID(format));
 4051: 
 4052:   status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
 4053: 		      TrioOutStreamStringMax, format, NULL, args);
 4054:   if (max > 0)
 4055:     *buffer = NIL;
 4056:   return status;
 4057: }
 4058: 
 4059: /*************************************************************************
 4060:  * snprintfcat
 4061:  * Appends the new string to the buffer string overwriting the '\0'
 4062:  * character at the end of buffer.
 4063:  */
 4064: TRIO_PUBLIC int
 4065: trio_snprintfcat
 4066: TRIO_VARGS4((buffer, max, format, va_alist),
 4067: 	    char *buffer,
 4068: 	    size_t max,
 4069: 	    TRIO_CONST char *format,
 4070: 	    TRIO_VA_DECL)
 4071: {
 4072:   int status;
 4073:   va_list args;
 4074:   size_t buf_len;
 4075: 
 4076:   TRIO_VA_START(args, format);
 4077: 
 4078:   assert(VALID(buffer));
 4079:   assert(VALID(format));
 4080: 
 4081:   buf_len = trio_length(buffer);
 4082:   buffer = &buffer[buf_len];
 4083: 
 4084:   status = TrioFormat(&buffer, max - 1 - buf_len,
 4085: 		      TrioOutStreamStringMax, format, &args, NULL);
 4086:   TRIO_VA_END(args);
 4087:   *buffer = NIL;
 4088:   return status;
 4089: }
 4090: 
 4091: TRIO_PUBLIC int
 4092: trio_vsnprintfcat
 4093: TRIO_ARGS4((buffer, max, format, args),
 4094: 	   char *buffer,
 4095: 	   size_t max,
 4096: 	   TRIO_CONST char *format,
 4097: 	   va_list args)
 4098: {
 4099:   int status;
 4100:   size_t buf_len;
 4101:   
 4102:   assert(VALID(buffer));
 4103:   assert(VALID(format));
 4104: 
 4105:   buf_len = trio_length(buffer);
 4106:   buffer = &buffer[buf_len];
 4107:   status = TrioFormat(&buffer, max - 1 - buf_len,
 4108: 		      TrioOutStreamStringMax, format, &args, NULL);
 4109:   *buffer = NIL;
 4110:   return status;
 4111: }
 4112: 
 4113: /*************************************************************************
 4114:  * trio_aprintf
 4115:  */
 4116: 
 4117: /* Deprecated */
 4118: TRIO_PUBLIC char *
 4119: trio_aprintf
 4120: TRIO_VARGS2((format, va_alist),
 4121: 	    TRIO_CONST char *format,
 4122: 	    TRIO_VA_DECL)
 4123: {
 4124:   va_list args;
 4125:   trio_string_t *info;
 4126:   char *result = NULL;
 4127: 
 4128:   assert(VALID(format));
 4129:   
 4130:   info = trio_xstring_duplicate("");
 4131:   if (info)
 4132:     {
 4133:       TRIO_VA_START(args, format);
 4134:       (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
 4135: 		       format, &args, NULL);
 4136:       TRIO_VA_END(args);
 4137: 
 4138:       trio_string_terminate(info);
 4139:       result = trio_string_extract(info);
 4140:       trio_string_destroy(info);
 4141:     }
 4142:   return result;
 4143: }
 4144: 
 4145: /* Deprecated */
 4146: TRIO_PUBLIC char *
 4147: trio_vaprintf
 4148: TRIO_ARGS2((format, args),
 4149: 	   TRIO_CONST char *format,
 4150: 	   va_list args)
 4151: {
 4152:   trio_string_t *info;
 4153:   char *result = NULL;
 4154:   
 4155:   assert(VALID(format));
 4156:   
 4157:   info = trio_xstring_duplicate("");
 4158:   if (info)
 4159:     {
 4160:       (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
 4161: 		       format, &args, NULL);
 4162:       trio_string_terminate(info);
 4163:       result = trio_string_extract(info);
 4164:       trio_string_destroy(info);
 4165:     }
 4166:   return result;
 4167: }
 4168: 
 4169: TRIO_PUBLIC int
 4170: trio_asprintf
 4171: TRIO_VARGS3((result, format, va_alist),
 4172: 	    char **result,
 4173: 	    TRIO_CONST char *format,
 4174: 	    TRIO_VA_DECL)
 4175: {
 4176:   va_list args;
 4177:   int status;
 4178:   trio_string_t *info;
 4179: 
 4180:   assert(VALID(format));
 4181: 
 4182:   *result = NULL;
 4183:   
 4184:   info = trio_xstring_duplicate("");
 4185:   if (info == NULL)
 4186:     {
 4187:       status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
 4188:     }
 4189:   else
 4190:     {
 4191:       TRIO_VA_START(args, format);
 4192:       status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
 4193: 			  format, &args, NULL);
 4194:       TRIO_VA_END(args);
 4195:       if (status >= 0)
 4196: 	{
 4197: 	  trio_string_terminate(info);
 4198: 	  *result = trio_string_extract(info);
 4199: 	}
 4200:       trio_string_destroy(info);
 4201:     }
 4202:   return status;
 4203: }
 4204: 
 4205: TRIO_PUBLIC int
 4206: trio_vasprintf
 4207: TRIO_ARGS3((result, format, args),
 4208: 	   char **result,
 4209: 	   TRIO_CONST char *format,
 4210: 	   va_list args)
 4211: {
 4212:   int status;
 4213:   trio_string_t *info;
 4214:   
 4215:   assert(VALID(format));
 4216: 
 4217:   *result = NULL;
 4218:   
 4219:   info = trio_xstring_duplicate("");
 4220:   if (info == NULL)
 4221:     {
 4222:       status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
 4223:     }
 4224:   else
 4225:     {
 4226:       status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
 4227: 			  format, &args, NULL);
 4228:       if (status >= 0)
 4229: 	{
 4230: 	  trio_string_terminate(info);
 4231: 	  *result = trio_string_extract(info);
 4232: 	}
 4233:       trio_string_destroy(info);
 4234:     }
 4235:   return status;
 4236: }
 4237: 
 4238: /** @} End of Printf documentation module */
 4239: 
 4240: /*************************************************************************
 4241:  *
 4242:  * CALLBACK
 4243:  *
 4244:  ************************************************************************/
 4245: 
 4246: #if defined(TRIO_DOCUMENTATION)
 4247: # include "doc/doc_register.h"
 4248: #endif
 4249: /**
 4250:    @addtogroup UserDefined
 4251:    @{
 4252: */
 4253: 
 4254: #if TRIO_EXTENSION
 4255: 
 4256: /*************************************************************************
 4257:  * trio_register
 4258:  */
 4259: 
 4260: /**
 4261:    Register new user-defined specifier.
 4262: 
 4263:    @param callback
 4264:    @param name
 4265:    @return Handle.
 4266:  */
 4267: TRIO_PUBLIC trio_pointer_t 
 4268: trio_register
 4269: TRIO_ARGS2((callback, name),
 4270: 	   trio_callback_t callback,
 4271: 	   TRIO_CONST char *name)
 4272: {
 4273:   trio_userdef_t *def;
 4274:   trio_userdef_t *prev = NULL;
 4275: 
 4276:   if (callback == NULL)
 4277:     return NULL;
 4278: 
 4279:   if (name)
 4280:     {
 4281:       /* Handle built-in namespaces */
 4282:       if (name[0] == ':')
 4283: 	{
 4284: 	  if (trio_equal(name, ":enter"))
 4285: 	    {
 4286: 	      internalEnterCriticalRegion = callback;
 4287: 	    }
 4288: 	  else if (trio_equal(name, ":leave"))
 4289: 	    {
 4290: 	      internalLeaveCriticalRegion = callback;
 4291: 	    }
 4292: 	  return NULL;
 4293: 	}
 4294:       
 4295:       /* Bail out if namespace is too long */
 4296:       if (trio_length(name) >= MAX_USER_NAME)
 4297: 	return NULL;
 4298:       
 4299:       /* Bail out if namespace already is registered */
 4300:       def = TrioFindNamespace(name, &prev);
 4301:       if (def)
 4302: 	return NULL;
 4303:     }
 4304:   
 4305:   def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
 4306:   if (def)
 4307:     {
 4308:       if (internalEnterCriticalRegion)
 4309: 	(void)internalEnterCriticalRegion(NULL);
 4310:       
 4311:       if (name)
 4312: 	{
 4313: 	  /* Link into internal list */
 4314: 	  if (prev == NULL)
 4315: 	    internalUserDef = def;
 4316: 	  else
 4317: 	    prev->next = def;
 4318: 	}
 4319:       /* Initialize */
 4320:       def->callback = callback;
 4321:       def->name = (name == NULL)
 4322: 	? NULL
 4323: 	: trio_duplicate(name);
 4324:       def->next = NULL;
 4325: 
 4326:       if (internalLeaveCriticalRegion)
 4327: 	(void)internalLeaveCriticalRegion(NULL);
 4328:     }
 4329:   return (trio_pointer_t)def;
 4330: }
 4331: 
 4332: /**
 4333:    Unregister an existing user-defined specifier.
 4334: 
 4335:    @param handle
 4336:  */
 4337: void
 4338: trio_unregister
 4339: TRIO_ARGS1((handle),
 4340: 	   trio_pointer_t handle)
 4341: {
 4342:   trio_userdef_t *self = (trio_userdef_t *)handle;
 4343:   trio_userdef_t *def;
 4344:   trio_userdef_t *prev = NULL;
 4345: 
 4346:   assert(VALID(self));
 4347: 
 4348:   if (self->name)
 4349:     {
 4350:       def = TrioFindNamespace(self->name, &prev);
 4351:       if (def)
 4352: 	{
 4353: 	  if (internalEnterCriticalRegion)
 4354: 	    (void)internalEnterCriticalRegion(NULL);
 4355: 	  
 4356: 	  if (prev == NULL)
 4357: 	    internalUserDef = NULL;
 4358: 	  else
 4359: 	    prev->next = def->next;
 4360: 	  
 4361: 	  if (internalLeaveCriticalRegion)
 4362: 	    (void)internalLeaveCriticalRegion(NULL);
 4363: 	}
 4364:       trio_destroy(self->name);
 4365:     }
 4366:   TRIO_FREE(self);
 4367: }
 4368: 
 4369: /*************************************************************************
 4370:  * trio_get_format [public]
 4371:  */
 4372: TRIO_CONST char *
 4373: trio_get_format
 4374: TRIO_ARGS1((ref),
 4375: 	   trio_pointer_t ref)
 4376: {
 4377: #if defined(FORMAT_USER_DEFINED)
 4378:   assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
 4379: #endif
 4380:   
 4381:   return (((trio_reference_t *)ref)->parameter->user_data);
 4382: }
 4383: 
 4384: /*************************************************************************
 4385:  * trio_get_argument [public]
 4386:  */
 4387: trio_pointer_t 
 4388: trio_get_argument
 4389: TRIO_ARGS1((ref),
 4390: 	   trio_pointer_t ref)
 4391: {
 4392: #if defined(FORMAT_USER_DEFINED)
 4393:   assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
 4394: #endif
 4395:   
 4396:   return ((trio_reference_t *)ref)->parameter->data.pointer;
 4397: }
 4398: 
 4399: /*************************************************************************
 4400:  * trio_get_width / trio_set_width [public]
 4401:  */
 4402: int
 4403: trio_get_width
 4404: TRIO_ARGS1((ref),
 4405: 	   trio_pointer_t ref)
 4406: {
 4407:   return ((trio_reference_t *)ref)->parameter->width;
 4408: }
 4409: 
 4410: void
 4411: trio_set_width
 4412: TRIO_ARGS2((ref, width),
 4413: 	   trio_pointer_t ref,
 4414: 	   int width)
 4415: {
 4416:   ((trio_reference_t *)ref)->parameter->width = width;
 4417: }
 4418: 
 4419: /*************************************************************************
 4420:  * trio_get_precision / trio_set_precision [public]
 4421:  */
 4422: int
 4423: trio_get_precision
 4424: TRIO_ARGS1((ref),
 4425: 	   trio_pointer_t ref)
 4426: {
 4427:   return (((trio_reference_t *)ref)->parameter->precision);
 4428: }
 4429: 
 4430: void
 4431: trio_set_precision
 4432: TRIO_ARGS2((ref, precision),
 4433: 	   trio_pointer_t ref,
 4434: 	   int precision)
 4435: {
 4436:   ((trio_reference_t *)ref)->parameter->precision = precision;
 4437: }
 4438: 
 4439: /*************************************************************************
 4440:  * trio_get_base / trio_set_base [public]
 4441:  */
 4442: int
 4443: trio_get_base
 4444: TRIO_ARGS1((ref),
 4445: 	   trio_pointer_t ref)
 4446: {
 4447:   return (((trio_reference_t *)ref)->parameter->base);
 4448: }
 4449: 
 4450: void
 4451: trio_set_base
 4452: TRIO_ARGS2((ref, base),
 4453: 	   trio_pointer_t ref,
 4454: 	   int base)
 4455: {
 4456:   ((trio_reference_t *)ref)->parameter->base = base;
 4457: }
 4458: 
 4459: /*************************************************************************
 4460:  * trio_get_long / trio_set_long [public]
 4461:  */
 4462: int
 4463: trio_get_long
 4464: TRIO_ARGS1((ref),
 4465: 	   trio_pointer_t ref)
 4466: {
 4467:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG)
 4468:     ? TRUE
 4469:     : FALSE;
 4470: }
 4471: 
 4472: void
 4473: trio_set_long
 4474: TRIO_ARGS2((ref, is_long),
 4475: 	   trio_pointer_t ref,
 4476: 	   int is_long)
 4477: {
 4478:   if (is_long)
 4479:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
 4480:   else
 4481:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
 4482: }
 4483: 
 4484: /*************************************************************************
 4485:  * trio_get_longlong / trio_set_longlong [public]
 4486:  */
 4487: int
 4488: trio_get_longlong
 4489: TRIO_ARGS1((ref),
 4490: 	   trio_pointer_t ref)
 4491: {
 4492:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD)
 4493:     ? TRUE
 4494:     : FALSE;
 4495: }
 4496: 
 4497: void
 4498: trio_set_longlong
 4499: TRIO_ARGS2((ref, is_longlong),
 4500: 	   trio_pointer_t ref,
 4501: 	   int is_longlong)
 4502: {
 4503:   if (is_longlong)
 4504:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
 4505:   else
 4506:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
 4507: }
 4508: 
 4509: /*************************************************************************
 4510:  * trio_get_longdouble / trio_set_longdouble [public]
 4511:  */
 4512: int
 4513: trio_get_longdouble
 4514: TRIO_ARGS1((ref),
 4515: 	   trio_pointer_t ref)
 4516: {
 4517:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE)
 4518:     ? TRUE
 4519:     : FALSE;
 4520: }
 4521: 
 4522: void
 4523: trio_set_longdouble
 4524: TRIO_ARGS2((ref, is_longdouble),
 4525: 	   trio_pointer_t ref,
 4526: 	   int is_longdouble)
 4527: {
 4528:   if (is_longdouble)
 4529:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
 4530:   else
 4531:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
 4532: }
 4533: 
 4534: /*************************************************************************
 4535:  * trio_get_short / trio_set_short [public]
 4536:  */
 4537: int
 4538: trio_get_short
 4539: TRIO_ARGS1((ref),
 4540: 	   trio_pointer_t ref)
 4541: {
 4542:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT)
 4543:     ? TRUE
 4544:     : FALSE;
 4545: }
 4546: 
 4547: void
 4548: trio_set_short
 4549: TRIO_ARGS2((ref, is_short),
 4550: 	   trio_pointer_t ref,
 4551: 	   int is_short)
 4552: {
 4553:   if (is_short)
 4554:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
 4555:   else
 4556:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
 4557: }
 4558: 
 4559: /*************************************************************************
 4560:  * trio_get_shortshort / trio_set_shortshort [public]
 4561:  */
 4562: int
 4563: trio_get_shortshort
 4564: TRIO_ARGS1((ref),
 4565: 	   trio_pointer_t ref)
 4566: {
 4567:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT)
 4568:     ? TRUE
 4569:     : FALSE;
 4570: }
 4571: 
 4572: void
 4573: trio_set_shortshort
 4574: TRIO_ARGS2((ref, is_shortshort),
 4575: 	   trio_pointer_t ref,
 4576: 	   int is_shortshort)
 4577: {
 4578:   if (is_shortshort)
 4579:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
 4580:   else
 4581:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
 4582: }
 4583: 
 4584: /*************************************************************************
 4585:  * trio_get_alternative / trio_set_alternative [public]
 4586:  */
 4587: int
 4588: trio_get_alternative
 4589: TRIO_ARGS1((ref),
 4590: 	   trio_pointer_t ref)
 4591: {
 4592:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE)
 4593:     ? TRUE
 4594:     : FALSE;
 4595: }
 4596: 
 4597: void
 4598: trio_set_alternative
 4599: TRIO_ARGS2((ref, is_alternative),
 4600: 	   trio_pointer_t ref,
 4601: 	   int is_alternative)
 4602: {
 4603:   if (is_alternative)
 4604:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
 4605:   else
 4606:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
 4607: }
 4608: 
 4609: /*************************************************************************
 4610:  * trio_get_alignment / trio_set_alignment [public]
 4611:  */
 4612: int
 4613: trio_get_alignment
 4614: TRIO_ARGS1((ref),
 4615: 	   trio_pointer_t ref)
 4616: {
 4617:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST)
 4618:     ? TRUE
 4619:     : FALSE;
 4620: }
 4621: 
 4622: void
 4623: trio_set_alignment
 4624: TRIO_ARGS2((ref, is_leftaligned),
 4625: 	   trio_pointer_t ref,
 4626: 	   int is_leftaligned)
 4627: {
 4628:   if (is_leftaligned)
 4629:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
 4630:   else
 4631:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
 4632: }
 4633: 
 4634: /*************************************************************************
 4635:  * trio_get_spacing /trio_set_spacing [public]
 4636:  */
 4637: int
 4638: trio_get_spacing
 4639: TRIO_ARGS1((ref),
 4640: 	   trio_pointer_t ref)
 4641: {
 4642:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE)
 4643:     ? TRUE
 4644:     : FALSE;
 4645: }
 4646: 
 4647: void
 4648: trio_set_spacing
 4649: TRIO_ARGS2((ref, is_space),
 4650: 	   trio_pointer_t ref,
 4651: 	   int is_space)
 4652: {
 4653:   if (is_space)
 4654:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
 4655:   else
 4656:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
 4657: }
 4658: 
 4659: /*************************************************************************
 4660:  * trio_get_sign / trio_set_sign [public]
 4661:  */
 4662: int
 4663: trio_get_sign
 4664: TRIO_ARGS1((ref),
 4665: 	   trio_pointer_t ref)
 4666: {
 4667:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN)
 4668:     ? TRUE
 4669:     : FALSE;
 4670: }
 4671: 
 4672: void
 4673: trio_set_sign
 4674: TRIO_ARGS2((ref, is_sign),
 4675: 	   trio_pointer_t ref,
 4676: 	   int is_sign)
 4677: {
 4678:   if (is_sign)
 4679:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
 4680:   else
 4681:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
 4682: }
 4683: 
 4684: /*************************************************************************
 4685:  * trio_get_padding / trio_set_padding [public]
 4686:  */
 4687: int
 4688: trio_get_padding
 4689: TRIO_ARGS1((ref),
 4690: 	   trio_pointer_t ref)
 4691: {
 4692:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING)
 4693:     ? TRUE
 4694:     : FALSE;
 4695: }
 4696: 
 4697: void
 4698: trio_set_padding
 4699: TRIO_ARGS2((ref, is_padding),
 4700: 	   trio_pointer_t ref,
 4701: 	   int is_padding)
 4702: {
 4703:   if (is_padding)
 4704:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
 4705:   else
 4706:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
 4707: }
 4708: 
 4709: /*************************************************************************
 4710:  * trio_get_quote / trio_set_quote [public]
 4711:  */
 4712: int
 4713: trio_get_quote
 4714: TRIO_ARGS1((ref),
 4715: 	   trio_pointer_t ref)
 4716: {
 4717:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE)
 4718:     ? TRUE
 4719:     : FALSE;
 4720: }
 4721: 
 4722: void
 4723: trio_set_quote
 4724: TRIO_ARGS2((ref, is_quote),
 4725: 	   trio_pointer_t ref,
 4726: 	   int is_quote)
 4727: {
 4728:   if (is_quote)
 4729:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
 4730:   else
 4731:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
 4732: }
 4733: 
 4734: /*************************************************************************
 4735:  * trio_get_upper / trio_set_upper [public]
 4736:  */
 4737: int
 4738: trio_get_upper
 4739: TRIO_ARGS1((ref),
 4740: 	   trio_pointer_t ref)
 4741: {
 4742:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER)
 4743:     ? TRUE
 4744:     : FALSE;
 4745: }
 4746: 
 4747: void
 4748: trio_set_upper
 4749: TRIO_ARGS2((ref, is_upper),
 4750: 	   trio_pointer_t ref,
 4751: 	   int is_upper)
 4752: {
 4753:   if (is_upper)
 4754:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
 4755:   else
 4756:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
 4757: }
 4758: 
 4759: /*************************************************************************
 4760:  * trio_get_largest / trio_set_largest [public]
 4761:  */
 4762: #if TRIO_C99
 4763: int
 4764: trio_get_largest
 4765: TRIO_ARGS1((ref),
 4766: 	   trio_pointer_t ref)
 4767: {
 4768:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T)
 4769:     ? TRUE
 4770:     : FALSE;
 4771: }
 4772: 
 4773: void
 4774: trio_set_largest
 4775: TRIO_ARGS2((ref, is_largest),
 4776: 	   trio_pointer_t ref,
 4777: 	   int is_largest)
 4778: {
 4779:   if (is_largest)
 4780:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
 4781:   else
 4782:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
 4783: }
 4784: #endif
 4785: 
 4786: /*************************************************************************
 4787:  * trio_get_ptrdiff / trio_set_ptrdiff [public]
 4788:  */
 4789: int
 4790: trio_get_ptrdiff
 4791: TRIO_ARGS1((ref),
 4792: 	   trio_pointer_t ref)
 4793: {
 4794:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T)
 4795:     ? TRUE
 4796:     : FALSE;
 4797: }
 4798: 
 4799: void
 4800: trio_set_ptrdiff
 4801: TRIO_ARGS2((ref, is_ptrdiff),
 4802: 	   trio_pointer_t ref,
 4803: 	   int is_ptrdiff)
 4804: {
 4805:   if (is_ptrdiff)
 4806:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
 4807:   else
 4808:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
 4809: }
 4810: 
 4811: /*************************************************************************
 4812:  * trio_get_size / trio_set_size [public]
 4813:  */
 4814: #if TRIO_C99
 4815: int
 4816: trio_get_size
 4817: TRIO_ARGS1((ref),
 4818: 	   trio_pointer_t ref)
 4819: {
 4820:   return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T)
 4821:     ? TRUE
 4822:     : FALSE;
 4823: }
 4824: 
 4825: void
 4826: trio_set_size
 4827: TRIO_ARGS2((ref, is_size),
 4828: 	   trio_pointer_t ref,
 4829: 	   int is_size)
 4830: {
 4831:   if (is_size)
 4832:     ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
 4833:   else
 4834:     ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
 4835: }
 4836: #endif
 4837: 
 4838: /*************************************************************************
 4839:  * trio_print_int [public]
 4840:  */
 4841: void
 4842: trio_print_int
 4843: TRIO_ARGS2((ref, number),
 4844: 	   trio_pointer_t ref,
 4845: 	   int number)
 4846: {
 4847:   trio_reference_t *self = (trio_reference_t *)ref;
 4848: 
 4849:   TrioWriteNumber(self->data,
 4850: 		  (trio_uintmax_t)number,
 4851: 		  self->parameter->flags,
 4852: 		  self->parameter->width,
 4853: 		  self->parameter->precision,
 4854: 		  self->parameter->base);
 4855: }
 4856: 
 4857: /*************************************************************************
 4858:  * trio_print_uint [public]
 4859:  */
 4860: void
 4861: trio_print_uint
 4862: TRIO_ARGS2((ref, number),
 4863: 	   trio_pointer_t ref,
 4864: 	   unsigned int number)
 4865: {
 4866:   trio_reference_t *self = (trio_reference_t *)ref;
 4867: 
 4868:   TrioWriteNumber(self->data,
 4869: 		  (trio_uintmax_t)number,
 4870: 		  self->parameter->flags | FLAGS_UNSIGNED,
 4871: 		  self->parameter->width,
 4872: 		  self->parameter->precision,
 4873: 		  self->parameter->base);
 4874: }
 4875: 
 4876: /*************************************************************************
 4877:  * trio_print_double [public]
 4878:  */
 4879: void
 4880: trio_print_double
 4881: TRIO_ARGS2((ref, number),
 4882: 	   trio_pointer_t ref,
 4883: 	   double number)
 4884: {
 4885:   trio_reference_t *self = (trio_reference_t *)ref;
 4886: 
 4887:   TrioWriteDouble(self->data,
 4888: 		  number,
 4889: 		  self->parameter->flags,
 4890: 		  self->parameter->width,
 4891: 		  self->parameter->precision,
 4892: 		  self->parameter->base);
 4893: }
 4894: 
 4895: /*************************************************************************
 4896:  * trio_print_string [public]
 4897:  */
 4898: void
 4899: trio_print_string
 4900: TRIO_ARGS2((ref, string),
 4901: 	   trio_pointer_t ref,
 4902: 	   char *string)
 4903: {
 4904:   trio_reference_t *self = (trio_reference_t *)ref;
 4905: 
 4906:   TrioWriteString(self->data,
 4907: 		  string,
 4908: 		  self->parameter->flags,
 4909: 		  self->parameter->width,
 4910: 		  self->parameter->precision);
 4911: }
 4912: 
 4913: /*************************************************************************
 4914:  * trio_print_ref [public]
 4915:  */
 4916: int
 4917: trio_print_ref
 4918: TRIO_VARGS3((ref, format, va_alist),
 4919: 	    trio_pointer_t ref,
 4920: 	    TRIO_CONST char *format,
 4921: 	    TRIO_VA_DECL)
 4922: {
 4923:   int status;
 4924:   va_list arglist;
 4925: 
 4926:   assert(VALID(format));
 4927:   
 4928:   TRIO_VA_START(arglist, format);
 4929:   status = TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
 4930:   TRIO_VA_END(arglist);
 4931:   return status;
 4932: }
 4933: 
 4934: /*************************************************************************
 4935:  * trio_vprint_ref [public]
 4936:  */
 4937: int
 4938: trio_vprint_ref
 4939: TRIO_ARGS3((ref, format, arglist),
 4940: 	   trio_pointer_t ref,
 4941: 	   TRIO_CONST char *format,
 4942: 	   va_list arglist)
 4943: {
 4944:   assert(VALID(format));
 4945:   
 4946:   return TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
 4947: }
 4948: 
 4949: /*************************************************************************
 4950:  * trio_printv_ref [public]
 4951:  */
 4952: int
 4953: trio_printv_ref
 4954: TRIO_ARGS3((ref, format, argarray),
 4955: 	   trio_pointer_t ref,
 4956: 	   TRIO_CONST char *format,
 4957: 	   trio_pointer_t *argarray)
 4958: {
 4959:   assert(VALID(format));
 4960:   
 4961:   return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray);
 4962: }
 4963: 
 4964: #endif /* TRIO_EXTENSION */
 4965: 
 4966: /*************************************************************************
 4967:  * trio_print_pointer [public]
 4968:  */
 4969: void
 4970: trio_print_pointer
 4971: TRIO_ARGS2((ref, pointer),
 4972: 	   trio_pointer_t ref,
 4973: 	   trio_pointer_t pointer)
 4974: {
 4975:   trio_reference_t *self = (trio_reference_t *)ref;
 4976:   trio_flags_t flags;
 4977:   trio_uintmax_t number;
 4978: 
 4979:   if (NULL == pointer)
 4980:     {
 4981:       TRIO_CONST char *string = internalNullString;
 4982:       while (*string)
 4983: 	self->data->OutStream(self->data, *string++);
 4984:     }
 4985:   else
 4986:     {
 4987:       /*
 4988:        * The subtraction of the null pointer is a workaround
 4989:        * to avoid a compiler warning. The performance overhead
 4990:        * is negligible (and likely to be removed by an
 4991:        * optimizing compiler). The (char *) casting is done
 4992:        * to please ANSI C++.
 4993:        */
 4994:       number = (trio_uintmax_t)((char *)pointer - (char *)0);
 4995:       /* Shrink to size of pointer */
 4996:       number &= (trio_uintmax_t)-1;
 4997:       flags = self->parameter->flags;
 4998:       flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
 4999: 	        FLAGS_NILPADDING);
 5000:       TrioWriteNumber(self->data,
 5001: 		      number,
 5002: 		      flags,
 5003: 		      POINTER_WIDTH,
 5004: 		      NO_PRECISION,
 5005: 		      BASE_HEX);
 5006:     }
 5007: }
 5008: 
 5009: /** @} End of UserDefined documentation module */
 5010: 
 5011: /*************************************************************************
 5012:  *
 5013:  * LOCALES
 5014:  *
 5015:  ************************************************************************/
 5016: 
 5017: /*************************************************************************
 5018:  * trio_locale_set_decimal_point
 5019:  *
 5020:  * Decimal point can only be one character. The input argument is a
 5021:  * string to enable multibyte characters. At most MB_LEN_MAX characters
 5022:  * will be used.
 5023:  */
 5024: TRIO_PUBLIC void
 5025: trio_locale_set_decimal_point
 5026: TRIO_ARGS1((decimalPoint),
 5027: 	   char *decimalPoint)
 5028: {
 5029: #if defined(USE_LOCALE)
 5030:   if (NULL == internalLocaleValues)
 5031:     {
 5032:       TrioSetLocale();
 5033:     }
 5034: #endif
 5035:   internalDecimalPointLength = trio_length(decimalPoint);
 5036:   if (internalDecimalPointLength == 1)
 5037:     {
 5038:       internalDecimalPoint = *decimalPoint;
 5039:     }
 5040:   else
 5041:     {
 5042:       internalDecimalPoint = NIL;
 5043:       trio_copy_max(internalDecimalPointString,
 5044: 		    sizeof(internalDecimalPointString),
 5045: 		    decimalPoint);
 5046:     }
 5047: }
 5048: 
 5049: /*************************************************************************
 5050:  * trio_locale_set_thousand_separator
 5051:  *
 5052:  * See trio_locale_set_decimal_point
 5053:  */
 5054: TRIO_PUBLIC void
 5055: trio_locale_set_thousand_separator
 5056: TRIO_ARGS1((thousandSeparator),
 5057: 	   char *thousandSeparator)
 5058: {
 5059: #if defined(USE_LOCALE)
 5060:   if (NULL == internalLocaleValues)
 5061:     {
 5062:       TrioSetLocale();
 5063:     }
 5064: #endif
 5065:   trio_copy_max(internalThousandSeparator,
 5066: 		sizeof(internalThousandSeparator),
 5067: 		thousandSeparator);
 5068:   internalThousandSeparatorLength = trio_length(internalThousandSeparator);
 5069: }
 5070: 
 5071: /*************************************************************************
 5072:  * trio_locale_set_grouping
 5073:  *
 5074:  * Array of bytes. Reversed order.
 5075:  *
 5076:  *  CHAR_MAX : No further grouping
 5077:  *  0        : Repeat last group for the remaining digits (not necessary
 5078:  *             as C strings are zero-terminated)
 5079:  *  n        : Set current group to n
 5080:  *
 5081:  * Same order as the grouping attribute in LC_NUMERIC.
 5082:  */
 5083: TRIO_PUBLIC void
 5084: trio_locale_set_grouping
 5085: TRIO_ARGS1((grouping),
 5086: 	   char *grouping)
 5087: {
 5088: #if defined(USE_LOCALE)
 5089:   if (NULL == internalLocaleValues)
 5090:     {
 5091:       TrioSetLocale();
 5092:     }
 5093: #endif
 5094:   trio_copy_max(internalGrouping,
 5095: 		sizeof(internalGrouping),
 5096: 		grouping);
 5097: }
 5098: 
 5099: 
 5100: /*************************************************************************
 5101:  *
 5102:  * SCANNING
 5103:  *
 5104:  ************************************************************************/
 5105: 
 5106: /*************************************************************************
 5107:  * TrioSkipWhitespaces
 5108:  */
 5109: TRIO_PRIVATE int
 5110: TrioSkipWhitespaces
 5111: TRIO_ARGS1((self),
 5112: 	   trio_class_t *self)
 5113: {
 5114:   int ch;
 5115: 
 5116:   ch = self->current;
 5117:   while (isspace(ch))
 5118:     {
 5119:       self->InStream(self, &ch);
 5120:     }
 5121:   return ch;
 5122: }
 5123: 
 5124: /*************************************************************************
 5125:  * TrioGetCollation
 5126:  */
 5127: #if TRIO_EXTENSION
 5128: TRIO_PRIVATE void
 5129: TrioGetCollation(TRIO_NOARGS)
 5130: {
 5131:   int i;
 5132:   int j;
 5133:   int k;
 5134:   char first[2];
 5135:   char second[2];
 5136: 
 5137:   /* This is computationally expensive */
 5138:   first[1] = NIL;
 5139:   second[1] = NIL;
 5140:   for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5141:     {
 5142:       k = 0;
 5143:       first[0] = (char)i;
 5144:       for (j = 0; j < MAX_CHARACTER_CLASS; j++)
 5145: 	{
 5146: 	  second[0] = (char)j;
 5147: 	  if (trio_equal_locale(first, second))
 5148: 	    internalCollationArray[i][k++] = (char)j;
 5149: 	}
 5150:       internalCollationArray[i][k] = NIL;
 5151:     }
 5152: }
 5153: #endif
 5154: 
 5155: /*************************************************************************
 5156:  * TrioGetCharacterClass
 5157:  *
 5158:  * FIXME:
 5159:  *  multibyte
 5160:  */
 5161: TRIO_PRIVATE int
 5162: TrioGetCharacterClass
 5163: TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass),
 5164: 	   TRIO_CONST char *format,
 5165: 	   int *indexPointer,
 5166: 	   trio_flags_t *flagsPointer,
 5167: 	   int *characterclass)
 5168: {
 5169:   int index = *indexPointer;
 5170:   int i;
 5171:   char ch;
 5172:   char range_begin;
 5173:   char range_end;
 5174: 
 5175:   *flagsPointer &= ~FLAGS_EXCLUDE;
 5176: 
 5177:   if (format[index] == QUALIFIER_CIRCUMFLEX)
 5178:     {
 5179:       *flagsPointer |= FLAGS_EXCLUDE;
 5180:       index++;
 5181:     }
 5182:   /*
 5183:    * If the ungroup character is at the beginning of the scanlist,
 5184:    * it will be part of the class, and a second ungroup character
 5185:    * must follow to end the group.
 5186:    */
 5187:   if (format[index] == SPECIFIER_UNGROUP)
 5188:     {
 5189:       characterclass[(int)SPECIFIER_UNGROUP]++;
 5190:       index++;
 5191:     }
 5192:   /*
 5193:    * Minus is used to specify ranges. To include minus in the class,
 5194:    * it must be at the beginning of the list
 5195:    */
 5196:   if (format[index] == QUALIFIER_MINUS)
 5197:     {
 5198:       characterclass[(int)QUALIFIER_MINUS]++;
 5199:       index++;
 5200:     }
 5201:   /* Collect characters */
 5202:   for (ch = format[index];
 5203:        (ch != SPECIFIER_UNGROUP) && (ch != NIL);
 5204:        ch = format[++index])
 5205:     {
 5206:       switch (ch)
 5207: 	{
 5208: 	case QUALIFIER_MINUS: /* Scanlist ranges */
 5209: 	  
 5210: 	  /*
 5211: 	   * Both C99 and UNIX98 describes ranges as implementation-
 5212: 	   * defined.
 5213: 	   *
 5214: 	   * We support the following behaviour (although this may
 5215: 	   * change as we become wiser)
 5216: 	   * - only increasing ranges, ie. [a-b] but not [b-a]
 5217: 	   * - transitive ranges, ie. [a-b-c] == [a-c]
 5218: 	   * - trailing minus, ie. [a-] is interpreted as an 'a'
 5219: 	   *   and a '-'
 5220: 	   * - duplicates (although we can easily convert these
 5221: 	   *   into errors)
 5222: 	   */
 5223: 	  range_begin = format[index - 1];
 5224: 	  range_end = format[++index];
 5225: 	  if (range_end == SPECIFIER_UNGROUP)
 5226: 	    {
 5227: 	      /* Trailing minus is included */
 5228: 	      characterclass[(int)ch]++;
 5229: 	      ch = range_end;
 5230: 	      break; /* for */
 5231: 	    }
 5232: 	  if (range_end == NIL)
 5233: 	    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 5234: 	  if (range_begin > range_end)
 5235: 	    return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
 5236: 	    
 5237: 	  for (i = (int)range_begin; i <= (int)range_end; i++)
 5238: 	    characterclass[i]++;
 5239: 	    
 5240: 	  ch = range_end;
 5241: 	  break;
 5242: 	  
 5243: #if TRIO_EXTENSION
 5244: 
 5245: 	case SPECIFIER_GROUP:
 5246: 	  
 5247: 	  switch (format[index + 1])
 5248: 	    {
 5249: 	    case QUALIFIER_DOT: /* Collating symbol */
 5250: 	      /*
 5251: 	       * FIXME: This will be easier to implement when multibyte
 5252: 	       * characters have been implemented. Until now, we ignore
 5253: 	       * this feature.
 5254: 	       */
 5255: 	      for (i = index + 2; ; i++)
 5256: 		{
 5257: 		  if (format[i] == NIL)
 5258: 		    /* Error in syntax */
 5259: 		    return -1;
 5260: 		  else if (format[i] == QUALIFIER_DOT)
 5261: 		    break; /* for */
 5262: 		}
 5263: 	      if (format[++i] != SPECIFIER_UNGROUP)
 5264: 		return -1;
 5265: 	      
 5266: 	      index = i;
 5267: 	      break;
 5268: 	  
 5269: 	    case QUALIFIER_EQUAL: /* Equivalence class expressions */
 5270: 	      {
 5271: 		unsigned int j;
 5272: 		unsigned int k;
 5273: 	    
 5274: 		if (internalCollationUnconverted)
 5275: 		  {
 5276: 		    /* Lazy evaluation of collation array */
 5277: 		    TrioGetCollation();
 5278: 		    internalCollationUnconverted = FALSE;
 5279: 		  }
 5280: 		for (i = index + 2; ; i++)
 5281: 		  {
 5282: 		    if (format[i] == NIL)
 5283: 		      /* Error in syntax */
 5284: 		      return -1;
 5285: 		    else if (format[i] == QUALIFIER_EQUAL)
 5286: 		      break; /* for */
 5287: 		    else
 5288: 		      {
 5289: 			/* Mark any equivalent character */
 5290: 			k = (unsigned int)format[i];
 5291: 			for (j = 0; internalCollationArray[k][j] != NIL; j++)
 5292: 			  characterclass[(int)internalCollationArray[k][j]]++;
 5293: 		      }
 5294: 		  }
 5295: 		if (format[++i] != SPECIFIER_UNGROUP)
 5296: 		  return -1;
 5297: 		
 5298: 		index = i;
 5299: 	      }
 5300: 	      break;
 5301: 	  
 5302: 	    case QUALIFIER_COLON: /* Character class expressions */
 5303: 	  
 5304: 	      if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
 5305: 				 &format[index]))
 5306: 		{
 5307: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5308: 		    if (isalnum(i))
 5309: 		      characterclass[i]++;
 5310: 		  index += sizeof(CLASS_ALNUM) - 1;
 5311: 		}
 5312: 	      else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
 5313: 				      &format[index]))
 5314: 		{
 5315: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5316: 		    if (isalpha(i))
 5317: 		      characterclass[i]++;
 5318: 		  index += sizeof(CLASS_ALPHA) - 1;
 5319: 		}
 5320: 	      else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
 5321: 				      &format[index]))
 5322: 		{
 5323: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5324: 		    if (iscntrl(i))
 5325: 		      characterclass[i]++;
 5326: 		  index += sizeof(CLASS_CNTRL) - 1;
 5327: 		}
 5328: 	      else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
 5329: 				      &format[index]))
 5330: 		{
 5331: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5332: 		    if (isdigit(i))
 5333: 		      characterclass[i]++;
 5334: 		  index += sizeof(CLASS_DIGIT) - 1;
 5335: 		}
 5336: 	      else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
 5337: 				      &format[index]))
 5338: 		{
 5339: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5340: 		    if (isgraph(i))
 5341: 		      characterclass[i]++;
 5342: 		  index += sizeof(CLASS_GRAPH) - 1;
 5343: 		}
 5344: 	      else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
 5345: 				      &format[index]))
 5346: 		{
 5347: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5348: 		    if (islower(i))
 5349: 		      characterclass[i]++;
 5350: 		  index += sizeof(CLASS_LOWER) - 1;
 5351: 		}
 5352: 	      else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
 5353: 				      &format[index]))
 5354: 		{
 5355: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5356: 		    if (isprint(i))
 5357: 		      characterclass[i]++;
 5358: 		  index += sizeof(CLASS_PRINT) - 1;
 5359: 		}
 5360: 	      else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
 5361: 				      &format[index]))
 5362: 		{
 5363: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5364: 		    if (ispunct(i))
 5365: 		      characterclass[i]++;
 5366: 		  index += sizeof(CLASS_PUNCT) - 1;
 5367: 		}
 5368: 	      else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
 5369: 				      &format[index]))
 5370: 		{
 5371: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5372: 		    if (isspace(i))
 5373: 		      characterclass[i]++;
 5374: 		  index += sizeof(CLASS_SPACE) - 1;
 5375: 		}
 5376: 	      else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
 5377: 				      &format[index]))
 5378: 		{
 5379: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5380: 		    if (isupper(i))
 5381: 		      characterclass[i]++;
 5382: 		  index += sizeof(CLASS_UPPER) - 1;
 5383: 		}
 5384: 	      else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
 5385: 				      &format[index]))
 5386: 		{
 5387: 		  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 5388: 		    if (isxdigit(i))
 5389: 		      characterclass[i]++;
 5390: 		  index += sizeof(CLASS_XDIGIT) - 1;
 5391: 		}
 5392: 	      else
 5393: 		{
 5394: 		  characterclass[(int)ch]++;
 5395: 		}
 5396: 	      break;
 5397: 
 5398: 	    default:
 5399: 	      characterclass[(int)ch]++;
 5400: 	      break;
 5401: 	    }
 5402: 	  break;
 5403: 	  
 5404: #endif /* TRIO_EXTENSION */
 5405: 	  
 5406: 	default:
 5407: 	  characterclass[(int)ch]++;
 5408: 	  break;
 5409: 	}
 5410:     }
 5411:   return 0;
 5412: }
 5413: 
 5414: /*************************************************************************
 5415:  * TrioReadNumber
 5416:  *
 5417:  * We implement our own number conversion in preference of strtol and
 5418:  * strtoul, because we must handle 'long long' and thousand separators.
 5419:  */
 5420: TRIO_PRIVATE BOOLEAN_T
 5421: TrioReadNumber
 5422: TRIO_ARGS5((self, target, flags, width, base),
 5423: 	   trio_class_t *self,
 5424: 	   trio_uintmax_t *target,
 5425: 	   trio_flags_t flags,
 5426: 	   int width,
 5427: 	   int base)
 5428: {
 5429:   trio_uintmax_t number = 0;
 5430:   int digit;
 5431:   int count;
 5432:   BOOLEAN_T isNegative = FALSE;
 5433:   BOOLEAN_T gotNumber = FALSE;
 5434:   int j;
 5435: 
 5436:   assert(VALID(self));
 5437:   assert(VALID(self->InStream));
 5438:   assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
 5439: 
 5440:   if (internalDigitsUnconverted)
 5441:     {
 5442:       /* Lazy evaluation of digits array */
 5443:       memset(internalDigitArray, -1, sizeof(internalDigitArray));
 5444:       for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
 5445: 	{
 5446: 	  internalDigitArray[(int)internalDigitsLower[j]] = j;
 5447: 	  internalDigitArray[(int)internalDigitsUpper[j]] = j;
 5448: 	}
 5449:       internalDigitsUnconverted = FALSE;
 5450:     }
 5451:   
 5452:   TrioSkipWhitespaces(self);
 5453:   
 5454:   if (!(flags & FLAGS_UNSIGNED))
 5455:     {
 5456:       /* Leading sign */
 5457:       if (self->current == '+')
 5458: 	{
 5459: 	  self->InStream(self, NULL);
 5460: 	}
 5461:       else if (self->current == '-')
 5462: 	{
 5463: 	  self->InStream(self, NULL);
 5464: 	  isNegative = TRUE;
 5465: 	}
 5466:     }
 5467:   
 5468:   count = self->processed;
 5469:   
 5470:   if (flags & FLAGS_ALTERNATIVE)
 5471:     {
 5472:       switch (base)
 5473: 	{
 5474: 	case NO_BASE:
 5475: 	case BASE_OCTAL:
 5476: 	case BASE_HEX:
 5477: 	case BASE_BINARY:
 5478: 	  if (self->current == '0')
 5479: 	    {
 5480: 	      self->InStream(self, NULL);
 5481: 	      if (self->current)
 5482: 		{
 5483: 		  if ((base == BASE_HEX) &&
 5484: 		      (trio_to_upper(self->current) == 'X'))
 5485: 		    {
 5486: 		      self->InStream(self, NULL);
 5487: 		    }
 5488: 		  else if ((base == BASE_BINARY) &&
 5489: 			   (trio_to_upper(self->current) == 'B'))
 5490: 		    {
 5491: 		      self->InStream(self, NULL);
 5492: 		    }
 5493: 		}
 5494: 	    }
 5495: 	  else
 5496: 	    return FALSE;
 5497: 	  break;
 5498: 	default:
 5499: 	  break;
 5500: 	}
 5501:     }
 5502: 
 5503:   while (((width == NO_WIDTH) || (self->processed - count < width)) &&
 5504: 	 (! ((self->current == EOF) || isspace(self->current))))
 5505:     {
 5506:       if (isascii(self->current))
 5507: 	{
 5508: 	  digit = internalDigitArray[self->current];
 5509: 	  /* Abort if digit is not allowed in the specified base */
 5510: 	  if ((digit == -1) || (digit >= base))
 5511: 	    break;
 5512: 	}
 5513:       else if (flags & FLAGS_QUOTE)
 5514: 	{
 5515: 	  /* Compare with thousands separator */
 5516: 	  for (j = 0; internalThousandSeparator[j] && self->current; j++)
 5517: 	    {
 5518: 	      if (internalThousandSeparator[j] != self->current)
 5519: 		break;
 5520: 
 5521: 	      self->InStream(self, NULL);
 5522: 	    }
 5523: 	  if (internalThousandSeparator[j])
 5524: 	    break; /* Mismatch */
 5525: 	  else
 5526: 	    continue; /* Match */
 5527: 	}
 5528:       else
 5529: 	break;
 5530:             
 5531:       number *= base;
 5532:       number += digit;
 5533:       gotNumber = TRUE; /* we need at least one digit */
 5534: 
 5535:       self->InStream(self, NULL);
 5536:     }
 5537: 
 5538:   /* Was anything read at all? */
 5539:   if (!gotNumber)
 5540:     return FALSE;
 5541:   
 5542:   if (target)
 5543:     *target = (isNegative) ? -((trio_intmax_t)number) : number;
 5544:   return TRUE;
 5545: }
 5546: 
 5547: /*************************************************************************
 5548:  * TrioReadChar
 5549:  */
 5550: TRIO_PRIVATE int
 5551: TrioReadChar
 5552: TRIO_ARGS4((self, target, flags, width),
 5553: 	   trio_class_t *self,
 5554: 	   char *target,
 5555: 	   trio_flags_t flags,
 5556: 	   int width)
 5557: {
 5558:   int i;
 5559:   char ch;
 5560:   trio_uintmax_t number;
 5561:   
 5562:   assert(VALID(self));
 5563:   assert(VALID(self->InStream));
 5564: 
 5565:   for (i = 0;
 5566:        (self->current != EOF) && (i < width);
 5567:        i++)
 5568:     {
 5569:       ch = (char)self->current;
 5570:       self->InStream(self, NULL);
 5571:       if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
 5572: 	{
 5573: 	  switch (self->current)
 5574: 	    {
 5575: 	    case '\\': ch = '\\'; break;
 5576: 	    case 'a': ch = '\007'; break;
 5577: 	    case 'b': ch = '\b'; break;
 5578: 	    case 'f': ch = '\f'; break;
 5579: 	    case 'n': ch = '\n'; break;
 5580: 	    case 'r': ch = '\r'; break;
 5581: 	    case 't': ch = '\t'; break;
 5582: 	    case 'v': ch = '\v'; break;
 5583: 	    default:
 5584: 	      if (isdigit(self->current))
 5585: 		{
 5586: 		  /* Read octal number */
 5587: 		  if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
 5588: 		    return 0;
 5589: 		  ch = (char)number;
 5590: 		}
 5591: 	      else if (trio_to_upper(self->current) == 'X')
 5592: 		{
 5593: 		  /* Read hexadecimal number */
 5594: 		  self->InStream(self, NULL);
 5595: 		  if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
 5596: 		    return 0;
 5597: 		  ch = (char)number;
 5598: 		}
 5599: 	      else
 5600: 		{
 5601: 		  ch = (char)self->current;
 5602: 		}
 5603: 	      break;
 5604: 	    }
 5605: 	}
 5606:       
 5607:       if (target)
 5608: 	target[i] = ch;
 5609:     }
 5610:   return i + 1;
 5611: }
 5612: 
 5613: /*************************************************************************
 5614:  * TrioReadString
 5615:  */
 5616: TRIO_PRIVATE BOOLEAN_T
 5617: TrioReadString
 5618: TRIO_ARGS4((self, target, flags, width),
 5619: 	   trio_class_t *self,
 5620: 	   char *target,
 5621: 	   trio_flags_t flags,
 5622: 	   int width)
 5623: {
 5624:   int i;
 5625:   
 5626:   assert(VALID(self));
 5627:   assert(VALID(self->InStream));
 5628: 
 5629:   TrioSkipWhitespaces(self);
 5630:     
 5631:   /*
 5632:    * Continue until end of string is reached, a whitespace is encountered,
 5633:    * or width is exceeded
 5634:    */
 5635:   for (i = 0;
 5636:        ((width == NO_WIDTH) || (i < width)) &&
 5637:        (! ((self->current == EOF) || isspace(self->current)));
 5638:        i++)
 5639:     {
 5640:       if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
 5641: 	break; /* for */
 5642:     }
 5643:   if (target)
 5644:     target[i] = NIL;
 5645:   return TRUE;
 5646: }
 5647: 
 5648: /*************************************************************************
 5649:  * TrioReadWideChar
 5650:  */
 5651: #if TRIO_WIDECHAR
 5652: TRIO_PRIVATE int
 5653: TrioReadWideChar
 5654: TRIO_ARGS4((self, target, flags, width),
 5655: 	   trio_class_t *self,
 5656: 	   trio_wchar_t *target,
 5657: 	   trio_flags_t flags,
 5658: 	   int width)
 5659: {
 5660:   int i;
 5661:   int j;
 5662:   int size;
 5663:   int amount = 0;
 5664:   trio_wchar_t wch;
 5665:   char buffer[MB_LEN_MAX + 1];
 5666:   
 5667:   assert(VALID(self));
 5668:   assert(VALID(self->InStream));
 5669: 
 5670:   for (i = 0;
 5671:        (self->current != EOF) && (i < width);
 5672:        i++)
 5673:     {
 5674:       if (isascii(self->current))
 5675: 	{
 5676: 	  if (TrioReadChar(self, buffer, flags, 1) == 0)
 5677: 	    return 0;
 5678: 	  buffer[1] = NIL;
 5679: 	}
 5680:       else
 5681: 	{
 5682: 	  /*
 5683: 	   * Collect a multibyte character, by enlarging buffer until
 5684: 	   * it contains a fully legal multibyte character, or the
 5685: 	   * buffer is full.
 5686: 	   */
 5687: 	  j = 0;
 5688: 	  do
 5689: 	    {
 5690: 	      buffer[j++] = (char)self->current;
 5691: 	      buffer[j] = NIL;
 5692: 	      self->InStream(self, NULL);
 5693: 	    }
 5694: 	  while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
 5695: 	}
 5696:       if (target)
 5697: 	{
 5698: 	  size = mbtowc(&wch, buffer, sizeof(buffer));
 5699: 	  if (size > 0)
 5700: 	    target[i] = wch;
 5701: 	}
 5702:       amount += size;
 5703:       self->InStream(self, NULL);
 5704:     }
 5705:   return amount;
 5706: }
 5707: #endif /* TRIO_WIDECHAR */
 5708: 
 5709: /*************************************************************************
 5710:  * TrioReadWideString
 5711:  */
 5712: #if TRIO_WIDECHAR
 5713: TRIO_PRIVATE BOOLEAN_T
 5714: TrioReadWideString
 5715: TRIO_ARGS4((self, target, flags, width),
 5716: 	   trio_class_t *self,
 5717: 	   trio_wchar_t *target,
 5718: 	   trio_flags_t flags,
 5719: 	   int width)
 5720: {
 5721:   int i;
 5722:   int size;
 5723:   
 5724:   assert(VALID(self));
 5725:   assert(VALID(self->InStream));
 5726: 
 5727:   TrioSkipWhitespaces(self);
 5728: 
 5729: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 5730:   (void)mblen(NULL, 0);
 5731: #endif
 5732:   
 5733:   /*
 5734:    * Continue until end of string is reached, a whitespace is encountered,
 5735:    * or width is exceeded
 5736:    */
 5737:   for (i = 0;
 5738:        ((width == NO_WIDTH) || (i < width)) &&
 5739:        (! ((self->current == EOF) || isspace(self->current)));
 5740:        )
 5741:     {
 5742:       size = TrioReadWideChar(self, &target[i], flags, 1);
 5743:       if (size == 0)
 5744: 	break; /* for */
 5745: 
 5746:       i += size;
 5747:     }
 5748:   if (target)
 5749:     target[i] = WCONST('\0');
 5750:   return TRUE;
 5751: }
 5752: #endif /* TRIO_WIDECHAR */
 5753: 
 5754: /*************************************************************************
 5755:  * TrioReadGroup
 5756:  *
 5757:  * FIXME: characterclass does not work with multibyte characters
 5758:  */
 5759: TRIO_PRIVATE BOOLEAN_T
 5760: TrioReadGroup
 5761: TRIO_ARGS5((self, target, characterclass, flags, width),
 5762: 	   trio_class_t *self,
 5763: 	   char *target,
 5764: 	   int *characterclass,
 5765: 	   trio_flags_t flags,
 5766: 	   int width)
 5767: {
 5768:   int ch;
 5769:   int i;
 5770:   
 5771:   assert(VALID(self));
 5772:   assert(VALID(self->InStream));
 5773: 
 5774:   ch = self->current;
 5775:   for (i = 0;
 5776:        ((width == NO_WIDTH) || (i < width)) &&
 5777:        (! ((ch == EOF) ||
 5778: 	   (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
 5779:        i++)
 5780:     {
 5781:       if (target)
 5782: 	target[i] = (char)ch;
 5783:       self->InStream(self, &ch);
 5784:     }
 5785:   
 5786:   if (target)
 5787:     target[i] = NIL;
 5788:   return TRUE;
 5789: }
 5790: 
 5791: /*************************************************************************
 5792:  * TrioReadDouble
 5793:  *
 5794:  * FIXME:
 5795:  *  add long double
 5796:  *  handle base
 5797:  */
 5798: TRIO_PRIVATE BOOLEAN_T
 5799: TrioReadDouble
 5800: TRIO_ARGS4((self, target, flags, width),
 5801: 	   trio_class_t *self,
 5802: 	   trio_pointer_t target,
 5803: 	   trio_flags_t flags,
 5804: 	   int width)
 5805: {
 5806:   int ch;
 5807:   char doubleString[512];
 5808:   int index = 0;
 5809:   int start;
 5810:   int j;
 5811:   BOOLEAN_T isHex = FALSE;
 5812: 
 5813:   doubleString[0] = 0;
 5814:   
 5815:   if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
 5816:     width = sizeof(doubleString) - 1;
 5817:   
 5818:   TrioSkipWhitespaces(self);
 5819:   
 5820:   /*
 5821:    * Read entire double number from stream. trio_to_double requires
 5822:    * a string as input, but InStream can be anything, so we have to
 5823:    * collect all characters.
 5824:    */
 5825:   ch = self->current;
 5826:   if ((ch == '+') || (ch == '-'))
 5827:     {
 5828:       doubleString[index++] = (char)ch;
 5829:       self->InStream(self, &ch);
 5830:       width--;
 5831:     }
 5832: 
 5833:   start = index;
 5834:   switch (ch)
 5835:     {
 5836:     case 'n':
 5837:     case 'N':
 5838:       /* Not-a-number */
 5839:       if (index != 0)
 5840: 	break;
 5841:       /* FALLTHROUGH */
 5842:     case 'i':
 5843:     case 'I':
 5844:       /* Infinity */
 5845:       while (isalpha(ch) && (index - start < width))
 5846: 	{
 5847: 	  doubleString[index++] = (char)ch;
 5848: 	  self->InStream(self, &ch);
 5849: 	}
 5850:       doubleString[index] = NIL;
 5851: 
 5852:       /* Case insensitive string comparison */
 5853:       if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
 5854: 	  trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
 5855: 	{
 5856: 	  if (flags & FLAGS_LONGDOUBLE)
 5857: 	    {
 5858: 	      if ((start == 1) && (doubleString[0] == '-'))
 5859: 		{
 5860: 		  *((trio_long_double_t *)target) = trio_ninf();
 5861: 		}
 5862: 	      else
 5863: 		{
 5864: 		  *((trio_long_double_t *)target) = trio_pinf();
 5865: 		}
 5866: 	    }
 5867: 	  else
 5868: 	    {
 5869: 	      if ((start == 1) && (doubleString[0] == '-'))
 5870: 		{
 5871: 		  *((double *)target) = trio_ninf();
 5872: 		}
 5873: 	      else
 5874: 		{
 5875: 		  *((double *)target) = trio_pinf();
 5876: 		}
 5877: 	    }
 5878: 	  return TRUE;
 5879: 	}
 5880:       if (trio_equal(doubleString, NAN_UPPER))
 5881: 	{
 5882: 	  /* NaN must not have a preceeding + nor - */
 5883: 	  if (flags & FLAGS_LONGDOUBLE)
 5884: 	    {
 5885: 	      *((trio_long_double_t *)target) = trio_nan();
 5886: 	    }
 5887: 	  else
 5888: 	    {
 5889: 	      *((double *)target) = trio_nan();
 5890: 	    }
 5891: 	  return TRUE;
 5892: 	}
 5893:       return FALSE;
 5894: 
 5895:     case '0':
 5896:       doubleString[index++] = (char)ch;
 5897:       self->InStream(self, &ch);
 5898:       if (trio_to_upper(ch) == 'X')
 5899: 	{
 5900: 	  isHex = TRUE;
 5901: 	  doubleString[index++] = (char)ch;
 5902: 	  self->InStream(self, &ch);
 5903: 	}
 5904:       break;
 5905:       
 5906:     default:
 5907:       break;
 5908:     }
 5909:   
 5910:   while ((ch != EOF) && (index - start < width))
 5911:     {
 5912:       /* Integer part */
 5913:       if (isHex ? isxdigit(ch) : isdigit(ch))
 5914: 	{
 5915: 	  doubleString[index++] = (char)ch;
 5916: 	  self->InStream(self, &ch);
 5917: 	}
 5918:       else if (flags & FLAGS_QUOTE)
 5919: 	{
 5920: 	  /* Compare with thousands separator */
 5921: 	  for (j = 0; internalThousandSeparator[j] && self->current; j++)
 5922: 	    {
 5923: 	      if (internalThousandSeparator[j] != self->current)
 5924: 		break;
 5925: 
 5926: 	      self->InStream(self, &ch);
 5927: 	    }
 5928: 	  if (internalThousandSeparator[j])
 5929: 	    break; /* Mismatch */
 5930: 	  else
 5931: 	    continue; /* Match */
 5932: 	}
 5933:       else
 5934: 	break; /* while */
 5935:     }
 5936:   if (ch == '.')
 5937:     {
 5938:       /* Decimal part */
 5939:       doubleString[index++] = (char)ch;
 5940:       self->InStream(self, &ch);
 5941:       while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
 5942: 	     (index - start < width))
 5943: 	{
 5944: 	  doubleString[index++] = (char)ch;
 5945: 	  self->InStream(self, &ch);
 5946: 	}
 5947:       if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E'))
 5948: 	{
 5949: 	  /* Exponent */
 5950: 	  doubleString[index++] = (char)ch;
 5951: 	  self->InStream(self, &ch);
 5952: 	  if ((ch == '+') || (ch == '-'))
 5953: 	    {
 5954: 	      doubleString[index++] = (char)ch;
 5955: 	      self->InStream(self, &ch);
 5956: 	    }
 5957: 	  while (isdigit(ch) && (index - start < width))
 5958: 	    {
 5959: 	      doubleString[index++] = (char)ch;
 5960: 	      self->InStream(self, &ch);
 5961: 	    }
 5962: 	}
 5963:     }
 5964: 
 5965:   if ((index == start) || (*doubleString == NIL))
 5966:     return FALSE;
 5967: 
 5968:   doubleString[index] = 0;
 5969:   
 5970:   if (flags & FLAGS_LONGDOUBLE)
 5971:     {
 5972:       *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL);
 5973:     }
 5974:   else
 5975:     {
 5976:       *((double *)target) = trio_to_double(doubleString, NULL);
 5977:     }
 5978:   return TRUE;
 5979: }
 5980: 
 5981: /*************************************************************************
 5982:  * TrioReadPointer
 5983:  */
 5984: TRIO_PRIVATE BOOLEAN_T
 5985: TrioReadPointer
 5986: TRIO_ARGS3((self, target, flags),
 5987: 	   trio_class_t *self,
 5988: 	   trio_pointer_t *target,
 5989: 	   trio_flags_t flags)
 5990: {
 5991:   trio_uintmax_t number;
 5992:   char buffer[sizeof(internalNullString)];
 5993: 
 5994:   flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
 5995:   
 5996:   if (TrioReadNumber(self,
 5997: 		     &number,
 5998: 		     flags,
 5999: 		     POINTER_WIDTH,
 6000: 		     BASE_HEX))
 6001:     {
 6002:       /*
 6003:        * The strange assignment of number is a workaround for a compiler
 6004:        * warning
 6005:        */
 6006:       if (target)
 6007: 	*target = (char *)0 + number;
 6008:       return TRUE;
 6009:     }
 6010:   else if (TrioReadString(self,
 6011: 			  (flags & FLAGS_IGNORE)
 6012: 			  ? NULL
 6013: 			  : buffer,
 6014: 			  0,
 6015: 			  sizeof(internalNullString) - 1))
 6016:     {  
 6017:       if (trio_equal_case(buffer, internalNullString))
 6018: 	{
 6019: 	  if (target)
 6020: 	    *target = NULL;
 6021: 	  return TRUE;
 6022: 	}
 6023:     }
 6024:   return FALSE;
 6025: }
 6026: 
 6027: /*************************************************************************
 6028:  * TrioScanProcess
 6029:  */
 6030: TRIO_PRIVATE int
 6031: TrioScanProcess
 6032: TRIO_ARGS3((data, format, parameters),
 6033: 	   trio_class_t *data,
 6034: 	   TRIO_CONST char *format,
 6035: 	   trio_parameter_t *parameters)
 6036: {
 6037: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 6038:   int charlen;
 6039:   int cnt;
 6040: #endif
 6041:   int assignment;
 6042:   int ch;
 6043:   int index; /* Index of format string */
 6044:   int i; /* Index of current parameter */
 6045:   trio_flags_t flags;
 6046:   int width;
 6047:   int base;
 6048:   trio_pointer_t pointer;
 6049: 
 6050:   assignment = 0;
 6051:   i = 0;
 6052:   index = 0;
 6053:   data->InStream(data, &ch);
 6054: 
 6055: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 6056:   (void)mblen(NULL, 0);
 6057: #endif
 6058: 
 6059:   while (format[index])
 6060:     {
 6061: #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 6062:       if (! isascii(format[index]))
 6063: 	{
 6064: 	  charlen = mblen(&format[index], MB_LEN_MAX);
 6065: 	  if (charlen != -1)
 6066: 	    {
 6067: 	      /* Compare multibyte characters in format string */
 6068: 	      for (cnt = 0; cnt < charlen - 1; cnt++)
 6069: 		{
 6070: 		  if (ch != format[index + cnt])
 6071: 		    {
 6072: 		      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 6073: 		    }
 6074: 		  data->InStream(data, &ch);
 6075: 		}
 6076: 	      continue; /* while characters left in formatting string */
 6077: 	    }
 6078: 	}
 6079: #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
 6080:       
 6081:       if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
 6082: 	{
 6083: 	  return (assignment > 0) ? assignment : EOF;
 6084: 	}
 6085:       
 6086:       if (CHAR_IDENTIFIER == format[index])
 6087: 	{
 6088: 	  if (CHAR_IDENTIFIER == format[index + 1])
 6089: 	    {
 6090: 	      /* Two % in format matches one % in input stream */
 6091: 	      if (CHAR_IDENTIFIER == ch)
 6092: 		{
 6093: 		  data->InStream(data, &ch);
 6094: 		  index += 2;
 6095: 		  continue; /* while format chars left */
 6096: 		}
 6097: 	      else
 6098: 		return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 6099: 	    }
 6100: 
 6101: 	  /* Skip the parameter entries */
 6102: 	  while (parameters[i].type == FORMAT_PARAMETER)
 6103: 	    i++;
 6104: 	  
 6105: 	  flags = parameters[i].flags;
 6106: 	  /* Find width */
 6107: 	  width = parameters[i].width;
 6108: 	  if (flags & FLAGS_WIDTH_PARAMETER)
 6109: 	    {
 6110: 	      /* Get width from parameter list */
 6111: 	      width = (int)parameters[width].data.number.as_signed;
 6112: 	    }
 6113: 	  /* Find base */
 6114: 	  base = parameters[i].base;
 6115: 	  if (flags & FLAGS_BASE_PARAMETER)
 6116: 	    {
 6117: 	      /* Get base from parameter list */
 6118: 	      base = (int)parameters[base].data.number.as_signed;
 6119: 	    }
 6120: 	  
 6121: 	  switch (parameters[i].type)
 6122: 	    {
 6123: 	    case FORMAT_INT:
 6124: 	      {
 6125: 		trio_uintmax_t number;
 6126: 
 6127: 		if (0 == base)
 6128: 		  base = BASE_DECIMAL;
 6129: 
 6130: 		if (!TrioReadNumber(data,
 6131: 				    &number,
 6132: 				    flags,
 6133: 				    width,
 6134: 				    base))
 6135: 		  return assignment;
 6136: 
 6137: 		if (!(flags & FLAGS_IGNORE))
 6138: 		  {
 6139: 		    assignment++;
 6140: 
 6141: 		    pointer = parameters[i].data.pointer;
 6142: #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
 6143: 		    if (flags & FLAGS_SIZE_T)
 6144: 		      *(size_t *)pointer = (size_t)number;
 6145: 		    else
 6146: #endif
 6147: #if defined(QUALIFIER_PTRDIFF_T)
 6148: 		    if (flags & FLAGS_PTRDIFF_T)
 6149: 		      *(ptrdiff_t *)pointer = (ptrdiff_t)number;
 6150: 		    else
 6151: #endif
 6152: #if defined(QUALIFIER_INTMAX_T)
 6153: 		    if (flags & FLAGS_INTMAX_T)
 6154: 		      *(trio_intmax_t *)pointer = (trio_intmax_t)number;
 6155: 		    else
 6156: #endif
 6157: 		    if (flags & FLAGS_QUAD)
 6158: 		      *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
 6159: 		    else if (flags & FLAGS_LONG)
 6160: 		      *(long int *)pointer = (long int)number;
 6161: 		    else if (flags & FLAGS_SHORT)
 6162: 		      *(short int *)pointer = (short int)number;
 6163: 		    else
 6164: 		      *(int *)pointer = (int)number;
 6165: 		  }
 6166: 	      }
 6167: 	      break; /* FORMAT_INT */
 6168: 	      
 6169: 	    case FORMAT_STRING:
 6170: #if TRIO_WIDECHAR
 6171: 	      if (flags & FLAGS_WIDECHAR)
 6172: 		{
 6173: 		  if (!TrioReadWideString(data,
 6174: 					  (flags & FLAGS_IGNORE)
 6175: 					  ? NULL
 6176: 					  : parameters[i].data.wstring,
 6177: 					  flags,
 6178: 					  width))
 6179: 		    return assignment;
 6180: 		}
 6181: 	      else
 6182: #endif
 6183: 		{
 6184: 		  if (!TrioReadString(data,
 6185: 				      (flags & FLAGS_IGNORE)
 6186: 				      ? NULL
 6187: 				      : parameters[i].data.string,
 6188: 				      flags,
 6189: 				      width))
 6190: 		    return assignment;
 6191: 		}
 6192: 	      if (!(flags & FLAGS_IGNORE))
 6193: 		assignment++;
 6194: 	      break; /* FORMAT_STRING */
 6195: 
 6196: 	    case FORMAT_DOUBLE:
 6197: 	      {
 6198: 		trio_pointer_t pointer;
 6199: 
 6200: 		if (flags & FLAGS_IGNORE)
 6201: 		  {
 6202: 		    pointer = NULL;
 6203: 		  }
 6204: 		else
 6205: 		  {
 6206: 		    pointer = (flags & FLAGS_LONGDOUBLE)
 6207: 		      ? (trio_pointer_t)parameters[i].data.longdoublePointer
 6208: 		      : (trio_pointer_t)parameters[i].data.doublePointer;
 6209: 		  }
 6210: 		if (!TrioReadDouble(data, pointer, flags, width))
 6211: 		  {
 6212: 		    return assignment;
 6213: 		  }
 6214: 		if (!(flags & FLAGS_IGNORE))
 6215: 		  {
 6216: 		    assignment++;
 6217: 		  }
 6218: 		break; /* FORMAT_DOUBLE */
 6219: 	      }
 6220: 	    case FORMAT_GROUP:
 6221: 	      {
 6222: 		int characterclass[MAX_CHARACTER_CLASS + 1];
 6223: 		int rc;
 6224: 
 6225: 		/* Skip over modifiers */
 6226: 		while (format[index] != SPECIFIER_GROUP)
 6227: 		  {
 6228: 		    index++;
 6229: 		  }
 6230: 		/* Skip over group specifier */
 6231: 		index++;
 6232: 		
 6233: 		memset(characterclass, 0, sizeof(characterclass));
 6234: 		rc = TrioGetCharacterClass(format,
 6235: 					   &index,
 6236: 					   &flags,
 6237: 					   characterclass);
 6238: 		if (rc < 0)
 6239: 		  return rc;
 6240: 
 6241: 		if (!TrioReadGroup(data,
 6242: 				   (flags & FLAGS_IGNORE)
 6243: 				   ? NULL
 6244: 				   : parameters[i].data.string,
 6245: 				   characterclass,
 6246: 				   flags,
 6247: 				   parameters[i].width))
 6248: 		  return assignment;
 6249: 		if (!(flags & FLAGS_IGNORE))
 6250: 		  assignment++;
 6251: 	      }
 6252: 	      break; /* FORMAT_GROUP */
 6253: 
 6254: 	    case FORMAT_COUNT:
 6255: 	      pointer = parameters[i].data.pointer;
 6256: 	      if (NULL != pointer)
 6257: 		{
 6258: 		  int count = data->committed;
 6259: 		  if (ch != EOF)
 6260: 		    count--; /* a character is read, but is not consumed yet */
 6261: #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
 6262: 		  if (flags & FLAGS_SIZE_T)
 6263: 		    *(size_t *)pointer = (size_t)count;
 6264: 		  else
 6265: #endif
 6266: #if defined(QUALIFIER_PTRDIFF_T)
 6267: 		  if (flags & FLAGS_PTRDIFF_T)
 6268: 		    *(ptrdiff_t *)pointer = (ptrdiff_t)count;
 6269: 		  else
 6270: #endif
 6271: #if defined(QUALIFIER_INTMAX_T)
 6272: 		  if (flags & FLAGS_INTMAX_T)
 6273: 		    *(trio_intmax_t *)pointer = (trio_intmax_t)count;
 6274: 		  else
 6275: #endif
 6276: 		  if (flags & FLAGS_QUAD)
 6277: 		    {
 6278: 		      *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
 6279: 		    }
 6280: 		  else if (flags & FLAGS_LONG)
 6281: 		    {
 6282: 		      *(long int *)pointer = (long int)count;
 6283: 		    }
 6284: 		  else if (flags & FLAGS_SHORT)
 6285: 		    {
 6286: 		      *(short int *)pointer = (short int)count;
 6287: 		    }
 6288: 		  else
 6289: 		    {
 6290: 		      *(int *)pointer = (int)count;
 6291: 		    }
 6292: 		}
 6293: 	      break; /* FORMAT_COUNT */
 6294: 	      
 6295: 	    case FORMAT_CHAR:
 6296: #if TRIO_WIDECHAR
 6297: 	      if (flags & FLAGS_WIDECHAR)
 6298: 		{
 6299: 		  if (TrioReadWideChar(data,
 6300: 				       (flags & FLAGS_IGNORE)
 6301: 				       ? NULL
 6302: 				       : parameters[i].data.wstring,
 6303: 				       flags,
 6304: 				       (width == NO_WIDTH) ? 1 : width) == 0)
 6305: 		    return assignment;
 6306: 		}
 6307: 	      else
 6308: #endif
 6309: 		{
 6310: 		  if (TrioReadChar(data,
 6311: 				   (flags & FLAGS_IGNORE)
 6312: 				   ? NULL
 6313: 				   : parameters[i].data.string,
 6314: 				   flags,
 6315: 				   (width == NO_WIDTH) ? 1 : width) == 0)
 6316: 		    return assignment;
 6317: 		}
 6318: 	      if (!(flags & FLAGS_IGNORE))
 6319: 		assignment++;
 6320: 	      break; /* FORMAT_CHAR */
 6321: 
 6322: 	    case FORMAT_POINTER:
 6323: 	      if (!TrioReadPointer(data,
 6324: 				   (flags & FLAGS_IGNORE)
 6325: 				   ? NULL
 6326: 				   : (trio_pointer_t *)parameters[i].data.pointer,
 6327: 				   flags))
 6328: 		return assignment;
 6329: 	      if (!(flags & FLAGS_IGNORE))
 6330: 		assignment++;
 6331: 	      break; /* FORMAT_POINTER */
 6332: 
 6333: 	    case FORMAT_PARAMETER:
 6334: 	      break; /* FORMAT_PARAMETER */
 6335: 
 6336: 	    default:
 6337: 	      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 6338: 	    }
 6339: 	  ch = data->current;
 6340: 	  index = parameters[i].indexAfterSpecifier;
 6341: 	  i++;
 6342: 	}
 6343:       else /* Not an % identifier */
 6344: 	{
 6345: 	  if (isspace((int)format[index]))
 6346: 	    {
 6347: 	      /* Whitespaces may match any amount of whitespaces */
 6348: 	      ch = TrioSkipWhitespaces(data);
 6349: 	    }
 6350: 	  else if (ch == format[index])
 6351: 	    {
 6352: 	      data->InStream(data, &ch);
 6353: 	    }
 6354: 	  else
 6355: 	    return assignment;
 6356: 	  
 6357: 	  index++;
 6358: 	}
 6359:     }
 6360:   return assignment;
 6361: }
 6362: 
 6363: /*************************************************************************
 6364:  * TrioScan
 6365:  */
 6366: TRIO_PRIVATE int
 6367: TrioScan
 6368: TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray),
 6369: 	   trio_pointer_t source,
 6370: 	   size_t sourceSize,
 6371: 	   void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
 6372: 	   TRIO_CONST char *format,
 6373: 	   va_list *arglist,
 6374: 	   trio_pointer_t *argarray)
 6375: {
 6376:   int status;
 6377:   trio_parameter_t parameters[MAX_PARAMETERS];
 6378:   trio_class_t data;
 6379: 
 6380:   assert(VALID(InStream));
 6381:   assert(VALID(format));
 6382: 
 6383:   memset(&data, 0, sizeof(data));
 6384:   data.InStream = InStream;
 6385:   data.location = (trio_pointer_t)source;
 6386:   data.max = sourceSize;
 6387:   data.error = 0;
 6388: 
 6389: #if defined(USE_LOCALE)
 6390:   if (NULL == internalLocaleValues)
 6391:     {
 6392:       TrioSetLocale();
 6393:     }
 6394: #endif
 6395:   
 6396:   status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
 6397:   if (status < 0)
 6398:     return status;
 6399: 
 6400:   status = TrioScanProcess(&data, format, parameters);
 6401:   if (data.error != 0)
 6402:     {
 6403:       status = data.error;
 6404:     }
 6405:   return status;
 6406: }
 6407: 
 6408: /*************************************************************************
 6409:  * TrioInStreamFile
 6410:  */
 6411: TRIO_PRIVATE void
 6412: TrioInStreamFile
 6413: TRIO_ARGS2((self, intPointer),
 6414: 	   trio_class_t *self,
 6415: 	   int *intPointer)
 6416: {
 6417:   FILE *file = (FILE *)self->location;
 6418: 
 6419:   assert(VALID(self));
 6420:   assert(VALID(file));
 6421: 
 6422:   self->current = fgetc(file);
 6423:   if (self->current == EOF)
 6424:     {
 6425:       self->error = (ferror(file))
 6426: 	? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
 6427: 	: TRIO_ERROR_RETURN(TRIO_EOF, 0);
 6428:     }
 6429:   else
 6430:     {
 6431:       self->processed++;
 6432:       self->committed++;
 6433:     }
 6434:   
 6435:   if (VALID(intPointer))
 6436:     {
 6437:       *intPointer = self->current;
 6438:     }
 6439: }
 6440: 
 6441: /*************************************************************************
 6442:  * TrioInStreamFileDescriptor
 6443:  */
 6444: TRIO_PRIVATE void
 6445: TrioInStreamFileDescriptor
 6446: TRIO_ARGS2((self, intPointer),
 6447: 	   trio_class_t *self,
 6448: 	   int *intPointer)
 6449: {
 6450:   int fd = *((int *)self->location);
 6451:   int size;
 6452:   unsigned char input;
 6453: 
 6454:   assert(VALID(self));
 6455: 
 6456:   size = read(fd, &input, sizeof(char));
 6457:   if (size == -1)
 6458:     {
 6459:       self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
 6460:       self->current = EOF;
 6461:     }
 6462:   else
 6463:     {
 6464:       self->current = (size == 0) ? EOF : input;
 6465:     }
 6466:   if (self->current != EOF)
 6467:     {
 6468:       self->committed++;
 6469:       self->processed++;
 6470:     }
 6471:   
 6472:   if (VALID(intPointer))
 6473:     {
 6474:       *intPointer = self->current;
 6475:     }
 6476: }
 6477: 
 6478: /*************************************************************************
 6479:  * TrioInStreamCustom
 6480:  */
 6481: TRIO_PRIVATE void
 6482: TrioInStreamCustom
 6483: TRIO_ARGS2((self, intPointer),
 6484: 	   trio_class_t *self,
 6485: 	   int *intPointer)
 6486: {
 6487:   trio_custom_t *data;
 6488:   
 6489:   assert(VALID(self));
 6490:   assert(VALID(self->location));
 6491: 
 6492:   data = (trio_custom_t *)self->location;
 6493: 
 6494:   self->current = (data->stream.in == NULL)
 6495:     ? NIL
 6496:     : (data->stream.in)(data->closure);
 6497:   
 6498:   if (self->current == NIL)
 6499:     {
 6500:       self->current = EOF;
 6501:     }
 6502:   else
 6503:     {
 6504:       self->processed++;
 6505:       self->committed++;
 6506:     }
 6507:   
 6508:   if (VALID(intPointer))
 6509:     {
 6510:       *intPointer = self->current;
 6511:     }
 6512: }
 6513: 
 6514: /*************************************************************************
 6515:  * TrioInStreamString
 6516:  */
 6517: TRIO_PRIVATE void
 6518: TrioInStreamString
 6519: TRIO_ARGS2((self, intPointer),
 6520: 	   trio_class_t *self,
 6521: 	   int *intPointer)
 6522: {
 6523:   unsigned char **buffer;
 6524: 
 6525:   assert(VALID(self));
 6526:   assert(VALID(self->location));
 6527: 
 6528:   buffer = (unsigned char **)self->location;
 6529:   self->current = (*buffer)[0];
 6530:   if (self->current == NIL)
 6531:     {
 6532:       self->current = EOF;
 6533:     }
 6534:   else
 6535:     {
 6536:       (*buffer)++;
 6537:       self->processed++;
 6538:       self->committed++;
 6539:     }
 6540:   
 6541:   if (VALID(intPointer))
 6542:     {
 6543:       *intPointer = self->current;
 6544:     }
 6545: }
 6546: 
 6547: /*************************************************************************
 6548:  *
 6549:  * Formatted scanning functions
 6550:  *
 6551:  ************************************************************************/
 6552: 
 6553: #if defined(TRIO_DOCUMENTATION)
 6554: # include "doc/doc_scanf.h"
 6555: #endif
 6556: /** @addtogroup Scanf
 6557:     @{
 6558: */
 6559: 
 6560: /*************************************************************************
 6561:  * scanf
 6562:  */
 6563: 
 6564: /**
 6565:    Scan characters from standard input stream.
 6566: 
 6567:    @param format Formatting string.
 6568:    @param ... Arguments.
 6569:    @return Number of scanned characters.
 6570:  */
 6571: TRIO_PUBLIC int
 6572: trio_scanf
 6573: TRIO_VARGS2((format, va_alist),
 6574: 	    TRIO_CONST char *format,
 6575: 	    TRIO_VA_DECL)
 6576: {
 6577:   int status;
 6578:   va_list args;
 6579: 
 6580:   assert(VALID(format));
 6581:   
 6582:   TRIO_VA_START(args, format);
 6583:   status = TrioScan((trio_pointer_t)stdin, 0,
 6584: 		    TrioInStreamFile,
 6585: 		    format, &args, NULL);
 6586:   TRIO_VA_END(args);
 6587:   return status;
 6588: }
 6589: 
 6590: TRIO_PUBLIC int
 6591: trio_vscanf
 6592: TRIO_ARGS2((format, args),
 6593: 	   TRIO_CONST char *format,
 6594: 	   va_list args)
 6595: {
 6596:   assert(VALID(format));
 6597:   
 6598:   return TrioScan((trio_pointer_t)stdin, 0,
 6599: 		  TrioInStreamFile,
 6600: 		  format, &args, NULL);
 6601: }
 6602: 
 6603: TRIO_PUBLIC int
 6604: trio_scanfv
 6605: TRIO_ARGS2((format, args),
 6606: 	   TRIO_CONST char *format,
 6607: 	   trio_pointer_t *args)
 6608: {
 6609:   assert(VALID(format));
 6610:   
 6611:   return TrioScan((trio_pointer_t)stdin, 0,
 6612: 		  TrioInStreamFile,
 6613: 		  format, NULL, args);
 6614: }
 6615: 
 6616: /*************************************************************************
 6617:  * fscanf
 6618:  */
 6619: TRIO_PUBLIC int
 6620: trio_fscanf
 6621: TRIO_VARGS3((file, format, va_alist),
 6622: 	    FILE *file,
 6623: 	    TRIO_CONST char *format,
 6624: 	    TRIO_VA_DECL)
 6625: {
 6626:   int status;
 6627:   va_list args;
 6628: 
 6629:   assert(VALID(file));
 6630:   assert(VALID(format));
 6631:   
 6632:   TRIO_VA_START(args, format);
 6633:   status = TrioScan((trio_pointer_t)file, 0,
 6634: 		    TrioInStreamFile,
 6635: 		    format, &args, NULL);
 6636:   TRIO_VA_END(args);
 6637:   return status;
 6638: }
 6639: 
 6640: TRIO_PUBLIC int
 6641: trio_vfscanf
 6642: TRIO_ARGS3((file, format, args),
 6643: 	   FILE *file,
 6644: 	   TRIO_CONST char *format,
 6645: 	   va_list args)
 6646: {
 6647:   assert(VALID(file));
 6648:   assert(VALID(format));
 6649:   
 6650:   return TrioScan((trio_pointer_t)file, 0,
 6651: 		  TrioInStreamFile,
 6652: 		  format, &args, NULL);
 6653: }
 6654: 
 6655: TRIO_PUBLIC int
 6656: trio_fscanfv
 6657: TRIO_ARGS3((file, format, args),
 6658: 	   FILE *file,
 6659: 	   TRIO_CONST char *format,
 6660: 	   trio_pointer_t *args)
 6661: {
 6662:   assert(VALID(file));
 6663:   assert(VALID(format));
 6664:   
 6665:   return TrioScan((trio_pointer_t)file, 0,
 6666: 		  TrioInStreamFile,
 6667: 		  format, NULL, args);
 6668: }
 6669: 
 6670: /*************************************************************************
 6671:  * dscanf
 6672:  */
 6673: TRIO_PUBLIC int
 6674: trio_dscanf
 6675: TRIO_VARGS3((fd, format, va_alist),
 6676: 	    int fd,
 6677: 	    TRIO_CONST char *format,
 6678: 	    TRIO_VA_DECL)
 6679: {
 6680:   int status;
 6681:   va_list args;
 6682: 
 6683:   assert(VALID(format));
 6684:   
 6685:   TRIO_VA_START(args, format);
 6686:   status = TrioScan((trio_pointer_t)&fd, 0,
 6687: 		    TrioInStreamFileDescriptor,
 6688: 		    format, &args, NULL);
 6689:   TRIO_VA_END(args);
 6690:   return status;
 6691: }
 6692: 
 6693: TRIO_PUBLIC int
 6694: trio_vdscanf
 6695: TRIO_ARGS3((fd, format, args),
 6696: 	   int fd,
 6697: 	   TRIO_CONST char *format,
 6698: 	   va_list args)
 6699: {
 6700:   assert(VALID(format));
 6701:   
 6702:   return TrioScan((trio_pointer_t)&fd, 0,
 6703: 		  TrioInStreamFileDescriptor,
 6704: 		  format, &args, NULL);
 6705: }
 6706: 
 6707: TRIO_PUBLIC int
 6708: trio_dscanfv
 6709: TRIO_ARGS3((fd, format, args),
 6710: 	   int fd,
 6711: 	   TRIO_CONST char *format,
 6712: 	   trio_pointer_t *args)
 6713: {
 6714:   assert(VALID(format));
 6715:   
 6716:   return TrioScan((trio_pointer_t)&fd, 0,
 6717: 		  TrioInStreamFileDescriptor,
 6718: 		  format, NULL, args);
 6719: }
 6720: 
 6721: /*************************************************************************
 6722:  * cscanf
 6723:  */
 6724: TRIO_PUBLIC int
 6725: trio_cscanf
 6726: TRIO_VARGS4((stream, closure, format, va_alist),
 6727: 	    trio_instream_t stream,
 6728: 	    trio_pointer_t closure,
 6729: 	    TRIO_CONST char *format,
 6730: 	    TRIO_VA_DECL)
 6731: {
 6732:   int status;
 6733:   va_list args;
 6734:   trio_custom_t data;
 6735: 
 6736:   assert(VALID(stream));
 6737:   assert(VALID(format));
 6738:   
 6739:   TRIO_VA_START(args, format);
 6740:   data.stream.in = stream;
 6741:   data.closure = closure;
 6742:   status = TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
 6743:   TRIO_VA_END(args);
 6744:   return status;
 6745: }
 6746: 
 6747: TRIO_PUBLIC int
 6748: trio_vcscanf
 6749: TRIO_ARGS4((stream, closure, format, args),
 6750: 	   trio_instream_t stream,
 6751: 	   trio_pointer_t closure,
 6752: 	   TRIO_CONST char *format,
 6753: 	   va_list args)
 6754: {
 6755:   trio_custom_t data;
 6756:   
 6757:   assert(VALID(stream));
 6758:   assert(VALID(format));
 6759: 
 6760:   data.stream.in = stream;
 6761:   data.closure = closure;
 6762:   return TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
 6763: }
 6764: 
 6765: TRIO_PUBLIC int
 6766: trio_cscanfv
 6767: TRIO_ARGS4((stream, closure, format, args),
 6768: 	   trio_instream_t stream,
 6769: 	   trio_pointer_t closure,
 6770: 	   TRIO_CONST char *format,
 6771: 	   trio_pointer_t *args)
 6772: {
 6773:   trio_custom_t data;
 6774:   
 6775:   assert(VALID(stream));
 6776:   assert(VALID(format));
 6777: 
 6778:   data.stream.in = stream;
 6779:   data.closure = closure;
 6780:   return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args);
 6781: }
 6782: 
 6783: /*************************************************************************
 6784:  * sscanf
 6785:  */
 6786: TRIO_PUBLIC int
 6787: trio_sscanf
 6788: TRIO_VARGS3((buffer, format, va_alist),
 6789: 	    TRIO_CONST char *buffer,
 6790: 	    TRIO_CONST char *format,
 6791: 	    TRIO_VA_DECL)
 6792: {
 6793:   int status;
 6794:   va_list args;
 6795: 
 6796:   assert(VALID(buffer));
 6797:   assert(VALID(format));
 6798:   
 6799:   TRIO_VA_START(args, format);
 6800:   status = TrioScan((trio_pointer_t)&buffer, 0,
 6801: 		    TrioInStreamString,
 6802: 		    format, &args, NULL);
 6803:   TRIO_VA_END(args);
 6804:   return status;
 6805: }
 6806: 
 6807: TRIO_PUBLIC int
 6808: trio_vsscanf
 6809: TRIO_ARGS3((buffer, format, args),
 6810: 	   TRIO_CONST char *buffer,
 6811: 	   TRIO_CONST char *format,
 6812: 	   va_list args)
 6813: {
 6814:   assert(VALID(buffer));
 6815:   assert(VALID(format));
 6816:   
 6817:   return TrioScan((trio_pointer_t)&buffer, 0,
 6818: 		  TrioInStreamString,
 6819: 		  format, &args, NULL);
 6820: }
 6821: 
 6822: TRIO_PUBLIC int
 6823: trio_sscanfv
 6824: TRIO_ARGS3((buffer, format, args),
 6825: 	   TRIO_CONST char *buffer,
 6826: 	   TRIO_CONST char *format,
 6827: 	   trio_pointer_t *args)
 6828: {
 6829:   assert(VALID(buffer));
 6830:   assert(VALID(format));
 6831:   
 6832:   return TrioScan((trio_pointer_t)&buffer, 0,
 6833: 		  TrioInStreamString,
 6834: 		  format, NULL, args);
 6835: }
 6836: 
 6837: /** @} End of Scanf documentation module */
 6838: 
 6839: /*************************************************************************
 6840:  * trio_strerror
 6841:  */
 6842: TRIO_PUBLIC TRIO_CONST char *
 6843: trio_strerror
 6844: TRIO_ARGS1((errorcode),
 6845: 	   int errorcode)
 6846: {
 6847:   /* Textual versions of the error codes */
 6848:   switch (TRIO_ERROR_CODE(errorcode))
 6849:     {
 6850:     case TRIO_EOF:
 6851:       return "End of file";
 6852:     case TRIO_EINVAL:
 6853:       return "Invalid argument";
 6854:     case TRIO_ETOOMANY:
 6855:       return "Too many arguments";
 6856:     case TRIO_EDBLREF:
 6857:       return "Double reference";
 6858:     case TRIO_EGAP:
 6859:       return "Reference gap";
 6860:     case TRIO_ENOMEM:
 6861:       return "Out of memory";
 6862:     case TRIO_ERANGE:
 6863:       return "Invalid range";
 6864:     case TRIO_ECUSTOM:
 6865:       return "Custom error";
 6866:     default:
 6867:       return "Unknown";
 6868:     }
 6869: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>