os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclBinary.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /* 
     2  * tclBinary.c --
     3  *
     4  *	This file contains the implementation of the "binary" Tcl built-in
     5  *	command and the Tcl binary data object.
     6  *
     7  * Copyright (c) 1997 by Sun Microsystems, Inc.
     8  * Copyright (c) 1998-1999 by Scriptics Corporation.
     9  * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
    10  *
    11  * See the file "license.terms" for information on usage and redistribution
    12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    13  *
    14  * RCS: @(#) $Id: tclBinary.c,v 1.13.2.4 2005/10/23 22:01:29 msofer Exp $
    15  */
    16 
    17 #include "tclInt.h"
    18 #include "tclPort.h"
    19 #include <math.h>
    20 
    21 /*
    22  * The following constants are used by GetFormatSpec to indicate various
    23  * special conditions in the parsing of a format specifier.
    24  */
    25 
    26 #define BINARY_ALL -1		/* Use all elements in the argument. */
    27 #define BINARY_NOCOUNT -2	/* No count was specified in format. */
    28 
    29 /*
    30  * The following defines the maximum number of different (integer)
    31  * numbers placed in the object cache by 'binary scan' before it bails
    32  * out and switches back to Plan A (creating a new object for each
    33  * value.)  Theoretically, it would be possible to keep the cache
    34  * about for the values that are already in it, but that makes the
    35  * code slower in practise when overflow happens, and makes little
    36  * odds the rest of the time (as measured on my machine.)  It is also
    37  * slower (on the sample I tried at least) to grow the cache to hold
    38  * all items we might want to put in it; presumably the extra cost of
    39  * managing the memory for the enlarged table outweighs the benefit
    40  * from allocating fewer objects.  This is probably because as the
    41  * number of objects increases, the likelihood of reuse of any
    42  * particular one drops, and there is very little gain from larger
    43  * maximum cache sizes (the value below is chosen to allow caching to
    44  * work in full with conversion of bytes.) - DKF
    45  */
    46 
    47 #define BINARY_SCAN_MAX_CACHE	260
    48 
    49 /*
    50  * Prototypes for local procedures defined in this file:
    51  */
    52 
    53 static void		DupByteArrayInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
    54 			    Tcl_Obj *copyPtr));
    55 static int		FormatNumber _ANSI_ARGS_((Tcl_Interp *interp, int type,
    56 			    Tcl_Obj *src, unsigned char **cursorPtr));
    57 static void		CopyNumber _ANSI_ARGS_((CONST VOID *from, VOID *to,
    58 			    unsigned int length));
    59 static void		FreeByteArrayInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr));
    60 static int		GetFormatSpec _ANSI_ARGS_((char **formatPtr,
    61 			    char *cmdPtr, int *countPtr));
    62 static Tcl_Obj *	ScanNumber _ANSI_ARGS_((unsigned char *buffer,
    63 			    int type, Tcl_HashTable **numberCachePtr));
    64 static int		SetByteArrayFromAny _ANSI_ARGS_((Tcl_Interp *interp,
    65 			    Tcl_Obj *objPtr));
    66 static void		UpdateStringOfByteArray _ANSI_ARGS_((Tcl_Obj *listPtr));
    67 static void		DeleteScanNumberCache _ANSI_ARGS_((
    68 			    Tcl_HashTable *numberCachePtr));
    69 
    70 /*
    71  * The following object type represents an array of bytes.  An array of
    72  * bytes is not equivalent to an internationalized string.  Conceptually, a
    73  * string is an array of 16-bit quantities organized as a sequence of properly
    74  * formed UTF-8 characters, while a ByteArray is an array of 8-bit quantities.
    75  * Accessor functions are provided to convert a ByteArray to a String or a
    76  * String to a ByteArray.  Two or more consecutive bytes in an array of bytes
    77  * may look like a single UTF-8 character if the array is casually treated as
    78  * a string.  But obtaining the String from a ByteArray is guaranteed to
    79  * produced properly formed UTF-8 sequences so that there is a one-to-one
    80  * map between bytes and characters.
    81  *
    82  * Converting a ByteArray to a String proceeds by casting each byte in the
    83  * array to a 16-bit quantity, treating that number as a Unicode character,
    84  * and storing the UTF-8 version of that Unicode character in the String.
    85  * For ByteArrays consisting entirely of values 1..127, the corresponding
    86  * String representation is the same as the ByteArray representation.
    87  *
    88  * Converting a String to a ByteArray proceeds by getting the Unicode
    89  * representation of each character in the String, casting it to a
    90  * byte by truncating the upper 8 bits, and then storing the byte in the
    91  * ByteArray.  Converting from ByteArray to String and back to ByteArray
    92  * is not lossy, but converting an arbitrary String to a ByteArray may be.
    93  */
    94 
    95 Tcl_ObjType tclByteArrayType = {
    96     "bytearray",
    97     FreeByteArrayInternalRep,
    98     DupByteArrayInternalRep,
    99     UpdateStringOfByteArray,
   100     SetByteArrayFromAny
   101 };
   102 
   103 /*
   104  * The following structure is the internal rep for a ByteArray object.
   105  * Keeps track of how much memory has been used and how much has been
   106  * allocated for the byte array to enable growing and shrinking of the
   107  * ByteArray object with fewer mallocs.  
   108  */
   109 
   110 typedef struct ByteArray {
   111     int used;			/* The number of bytes used in the byte
   112 				 * array. */
   113     int allocated;		/* The amount of space actually allocated
   114 				 * minus 1 byte. */
   115     unsigned char bytes[4];	/* The array of bytes.  The actual size of
   116 				 * this field depends on the 'allocated' field
   117 				 * above. */
   118 } ByteArray;
   119 
   120 #define BYTEARRAY_SIZE(len)	\
   121 		((unsigned) (sizeof(ByteArray) - 4 + (len)))
   122 #define GET_BYTEARRAY(objPtr) \
   123 		((ByteArray *) (objPtr)->internalRep.otherValuePtr)
   124 #define SET_BYTEARRAY(objPtr, baPtr) \
   125 		(objPtr)->internalRep.otherValuePtr = (VOID *) (baPtr)
   126 
   127 
   128 /*
   129  *---------------------------------------------------------------------------
   130  *
   131  * Tcl_NewByteArrayObj --
   132  *
   133  *	This procedure is creates a new ByteArray object and initializes
   134  *	it from the given array of bytes.
   135  *
   136  * Results:
   137  *	The newly create object is returned.  This object will have no
   138  *	initial string representation.  The returned object has a ref count
   139  *	of 0.
   140  *
   141  * Side effects:
   142  *	Memory allocated for new object and copy of byte array argument.
   143  *
   144  *---------------------------------------------------------------------------
   145  */
   146 
   147 #ifdef TCL_MEM_DEBUG
   148 #undef Tcl_NewByteArrayObj
   149 
   150 
   151 EXPORT_C Tcl_Obj *
   152 Tcl_NewByteArrayObj(bytes, length)
   153     CONST unsigned char *bytes;	/* The array of bytes used to initialize
   154 				 * the new object. */
   155     int length;			/* Length of the array of bytes, which must
   156 				 * be >= 0. */
   157 {
   158     return Tcl_DbNewByteArrayObj(bytes, length, "unknown", 0);
   159 }
   160 
   161 #else /* if not TCL_MEM_DEBUG */
   162 
   163 EXPORT_C Tcl_Obj *
   164 Tcl_NewByteArrayObj(bytes, length)
   165     CONST unsigned char *bytes;	/* The array of bytes used to initialize
   166 				 * the new object. */
   167     int length;			/* Length of the array of bytes, which must
   168 				 * be >= 0. */
   169 {
   170     Tcl_Obj *objPtr;
   171 
   172     TclNewObj(objPtr);
   173     Tcl_SetByteArrayObj(objPtr, bytes, length);
   174     return objPtr;
   175 }
   176 #endif /* TCL_MEM_DEBUG */
   177 
   178 /*
   179  *---------------------------------------------------------------------------
   180  *
   181  * Tcl_DbNewByteArrayObj --
   182  *
   183  *	This procedure is normally called when debugging: i.e., when
   184  *	TCL_MEM_DEBUG is defined. It is the same as the Tcl_NewByteArrayObj
   185  *	above except that it calls Tcl_DbCkalloc directly with the file name
   186  *	and line number from its caller. This simplifies debugging since then
   187  *	the [memory active] command will report the correct file name and line
   188  *	number when reporting objects that haven't been freed.
   189  *
   190  *	When TCL_MEM_DEBUG is not defined, this procedure just returns the
   191  *	result of calling Tcl_NewByteArrayObj.
   192  *
   193  * Results:
   194  *	The newly create object is returned.  This object will have no
   195  *	initial string representation.  The returned object has a ref count
   196  *	of 0.
   197  *
   198  * Side effects:
   199  *	Memory allocated for new object and copy of byte array argument.
   200  *
   201  *---------------------------------------------------------------------------
   202  */
   203 
   204 #ifdef TCL_MEM_DEBUG
   205 
   206 EXPORT_C Tcl_Obj *
   207 Tcl_DbNewByteArrayObj(bytes, length, file, line)
   208     CONST unsigned char *bytes;	/* The array of bytes used to initialize
   209 				 * the new object. */
   210     int length;			/* Length of the array of bytes, which must
   211 				 * be >= 0. */
   212     CONST char *file;		/* The name of the source file calling this
   213 				 * procedure; used for debugging. */
   214     int line;			/* Line number in the source file; used
   215 				 * for debugging. */
   216 {
   217     Tcl_Obj *objPtr;
   218 
   219     TclDbNewObj(objPtr, file, line);
   220     Tcl_SetByteArrayObj(objPtr, bytes, length);
   221     return objPtr;
   222 }
   223 
   224 #else /* if not TCL_MEM_DEBUG */
   225 
   226 EXPORT_C Tcl_Obj *
   227 Tcl_DbNewByteArrayObj(bytes, length, file, line)
   228     CONST unsigned char *bytes;	/* The array of bytes used to initialize
   229 				 * the new object. */
   230     int length;			/* Length of the array of bytes, which must
   231 				 * be >= 0. */
   232     CONST char *file;		/* The name of the source file calling this
   233 				 * procedure; used for debugging. */
   234     int line;			/* Line number in the source file; used
   235 				 * for debugging. */
   236 {
   237     return Tcl_NewByteArrayObj(bytes, length);
   238 }
   239 #endif /* TCL_MEM_DEBUG */
   240 
   241 /*
   242  *---------------------------------------------------------------------------
   243  *
   244  * Tcl_SetByteArrayObj --
   245  *
   246  *	Modify an object to be a ByteArray object and to have the specified
   247  *	array of bytes as its value.
   248  *
   249  * Results:
   250  *	None.
   251  *
   252  * Side effects:
   253  *	The object's old string rep and internal rep is freed.
   254  *	Memory allocated for copy of byte array argument.
   255  *
   256  *----------------------------------------------------------------------
   257  */
   258 
   259 EXPORT_C void
   260 Tcl_SetByteArrayObj(objPtr, bytes, length)
   261     Tcl_Obj *objPtr;		/* Object to initialize as a ByteArray. */
   262     CONST unsigned char *bytes;	/* The array of bytes to use as the new
   263 				 * value. */
   264     int length;			/* Length of the array of bytes, which must
   265 				 * be >= 0. */
   266 {
   267     Tcl_ObjType *typePtr;
   268     ByteArray *byteArrayPtr;
   269 
   270     if (Tcl_IsShared(objPtr)) {
   271 	panic("Tcl_SetByteArrayObj called with shared object");
   272     }
   273     typePtr = objPtr->typePtr;
   274     if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
   275 	(*typePtr->freeIntRepProc)(objPtr);
   276     }
   277     Tcl_InvalidateStringRep(objPtr);
   278 
   279     byteArrayPtr = (ByteArray *) ckalloc(BYTEARRAY_SIZE(length));
   280     byteArrayPtr->used = length;
   281     byteArrayPtr->allocated = length;
   282     memcpy((VOID *) byteArrayPtr->bytes, (VOID *) bytes, (size_t) length);
   283 
   284     objPtr->typePtr = &tclByteArrayType;
   285     SET_BYTEARRAY(objPtr, byteArrayPtr);
   286 }
   287 
   288 /*
   289  *----------------------------------------------------------------------
   290  *
   291  * Tcl_GetByteArrayFromObj --
   292  *
   293  *	Attempt to get the array of bytes from the Tcl object.  If the
   294  *	object is not already a ByteArray object, an attempt will be
   295  *	made to convert it to one.
   296  *
   297  * Results:
   298  *	Pointer to array of bytes representing the ByteArray object.
   299  *
   300  * Side effects:
   301  *	Frees old internal rep.  Allocates memory for new internal rep.
   302  *
   303  *----------------------------------------------------------------------
   304  */
   305 
   306 EXPORT_C unsigned char *
   307 Tcl_GetByteArrayFromObj(objPtr, lengthPtr)
   308     Tcl_Obj *objPtr;		/* The ByteArray object. */
   309     int *lengthPtr;		/* If non-NULL, filled with length of the
   310 				 * array of bytes in the ByteArray object. */
   311 {
   312     ByteArray *baPtr;
   313     
   314     SetByteArrayFromAny(NULL, objPtr);
   315     baPtr = GET_BYTEARRAY(objPtr);
   316 
   317     if (lengthPtr != NULL) {
   318 	*lengthPtr = baPtr->used;
   319     }
   320     return (unsigned char *) baPtr->bytes;
   321 }
   322 
   323 /*
   324  *----------------------------------------------------------------------
   325  *
   326  * Tcl_SetByteArrayLength --
   327  *
   328  *	This procedure changes the length of the byte array for this
   329  *	object.  Once the caller has set the length of the array, it
   330  *	is acceptable to directly modify the bytes in the array up until
   331  *	Tcl_GetStringFromObj() has been called on this object.
   332  *
   333  * Results:
   334  *	The new byte array of the specified length.
   335  *
   336  * Side effects:
   337  *	Allocates enough memory for an array of bytes of the requested
   338  *	size.  When growing the array, the old array is copied to the
   339  *	new array; new bytes are undefined.  When shrinking, the
   340  *	old array is truncated to the specified length.
   341  *
   342  *---------------------------------------------------------------------------
   343  */
   344 
   345 EXPORT_C unsigned char *
   346 Tcl_SetByteArrayLength(objPtr, length)
   347     Tcl_Obj *objPtr;		/* The ByteArray object. */
   348     int length;			/* New length for internal byte array. */
   349 {
   350     ByteArray *byteArrayPtr, *newByteArrayPtr;
   351     
   352     if (Tcl_IsShared(objPtr)) {
   353 	panic("Tcl_SetObjLength called with shared object");
   354     }
   355     if (objPtr->typePtr != &tclByteArrayType) {
   356 	SetByteArrayFromAny(NULL, objPtr);
   357     }
   358 
   359     byteArrayPtr = GET_BYTEARRAY(objPtr);
   360     if (length > byteArrayPtr->allocated) {
   361 	newByteArrayPtr = (ByteArray *) ckalloc(BYTEARRAY_SIZE(length));
   362 	newByteArrayPtr->used = length;
   363 	newByteArrayPtr->allocated = length;
   364 	memcpy((VOID *) newByteArrayPtr->bytes,
   365 		(VOID *) byteArrayPtr->bytes, (size_t) byteArrayPtr->used);
   366 	ckfree((char *) byteArrayPtr);
   367 	byteArrayPtr = newByteArrayPtr;
   368 	SET_BYTEARRAY(objPtr, byteArrayPtr);
   369     }
   370     Tcl_InvalidateStringRep(objPtr);
   371     byteArrayPtr->used = length;
   372     return byteArrayPtr->bytes;
   373 }
   374 
   375 /*
   376  *---------------------------------------------------------------------------
   377  *
   378  * SetByteArrayFromAny --
   379  *
   380  *	Generate the ByteArray internal rep from the string rep.
   381  *
   382  * Results:
   383  *	The return value is always TCL_OK.
   384  *
   385  * Side effects:
   386  *	A ByteArray object is stored as the internal rep of objPtr.
   387  *
   388  *---------------------------------------------------------------------------
   389  */
   390 
   391 static int
   392 SetByteArrayFromAny(interp, objPtr)
   393     Tcl_Interp *interp;		/* Not used. */
   394     Tcl_Obj *objPtr;		/* The object to convert to type ByteArray. */
   395 {
   396     Tcl_ObjType *typePtr;
   397     int length;
   398     char *src, *srcEnd;
   399     unsigned char *dst;
   400     ByteArray *byteArrayPtr;
   401     Tcl_UniChar ch;
   402     
   403     typePtr = objPtr->typePtr;
   404     if (typePtr != &tclByteArrayType) {
   405 	src = Tcl_GetStringFromObj(objPtr, &length);
   406 	srcEnd = src + length;
   407 
   408 	byteArrayPtr = (ByteArray *) ckalloc(BYTEARRAY_SIZE(length));
   409 	for (dst = byteArrayPtr->bytes; src < srcEnd; ) {
   410 	    src += Tcl_UtfToUniChar(src, &ch);
   411 	    *dst++ = (unsigned char) ch;
   412 	}
   413 
   414 	byteArrayPtr->used = dst - byteArrayPtr->bytes;
   415 	byteArrayPtr->allocated = length;
   416 
   417 	if ((typePtr != NULL) && (typePtr->freeIntRepProc) != NULL) {
   418 	    (*typePtr->freeIntRepProc)(objPtr);
   419 	}
   420 	objPtr->typePtr = &tclByteArrayType;
   421 	SET_BYTEARRAY(objPtr, byteArrayPtr);
   422     }
   423     return TCL_OK;
   424 }
   425 
   426 /*
   427  *----------------------------------------------------------------------
   428  *
   429  * FreeByteArrayInternalRep --
   430  *
   431  *	Deallocate the storage associated with a ByteArray data object's
   432  *	internal representation.
   433  *
   434  * Results:
   435  *	None.
   436  *
   437  * Side effects:
   438  *	Frees memory. 
   439  *
   440  *----------------------------------------------------------------------
   441  */
   442 
   443 static void
   444 FreeByteArrayInternalRep(objPtr)
   445     Tcl_Obj *objPtr;		/* Object with internal rep to free. */
   446 {
   447     ckfree((char *) GET_BYTEARRAY(objPtr));
   448 }
   449 
   450 /*
   451  *---------------------------------------------------------------------------
   452  *
   453  * DupByteArrayInternalRep --
   454  *
   455  *	Initialize the internal representation of a ByteArray Tcl_Obj
   456  *	to a copy of the internal representation of an existing ByteArray
   457  *	object. 
   458  *
   459  * Results:
   460  *	None.
   461  *
   462  * Side effects:
   463  *	Allocates memory.
   464  *
   465  *---------------------------------------------------------------------------
   466  */
   467 
   468 static void
   469 DupByteArrayInternalRep(srcPtr, copyPtr)
   470     Tcl_Obj *srcPtr;		/* Object with internal rep to copy. */
   471     Tcl_Obj *copyPtr;		/* Object with internal rep to set. */
   472 {
   473     int length;
   474     ByteArray *srcArrayPtr, *copyArrayPtr;    
   475 
   476     srcArrayPtr = GET_BYTEARRAY(srcPtr);
   477     length = srcArrayPtr->used;
   478 
   479     copyArrayPtr = (ByteArray *) ckalloc(BYTEARRAY_SIZE(length));
   480     copyArrayPtr->used = length;
   481     copyArrayPtr->allocated = length;
   482     memcpy((VOID *) copyArrayPtr->bytes, (VOID *) srcArrayPtr->bytes,
   483 	    (size_t) length);
   484     SET_BYTEARRAY(copyPtr, copyArrayPtr);
   485 
   486     copyPtr->typePtr = &tclByteArrayType;
   487 }
   488 
   489 /*
   490  *---------------------------------------------------------------------------
   491  *
   492  * UpdateStringOfByteArray --
   493  *
   494  *	Update the string representation for a ByteArray data object.
   495  *	Note: This procedure does not invalidate an existing old string rep
   496  *	so storage will be lost if this has not already been done. 
   497  *
   498  * Results:
   499  *	None.
   500  *
   501  * Side effects:
   502  *	The object's string is set to a valid string that results from
   503  *	the ByteArray-to-string conversion.
   504  *
   505  *	The object becomes a string object -- the internal rep is
   506  *	discarded and the typePtr becomes NULL.
   507  *
   508  *---------------------------------------------------------------------------
   509  */
   510 
   511 static void
   512 UpdateStringOfByteArray(objPtr)
   513     Tcl_Obj *objPtr;		/* ByteArray object whose string rep to
   514 				 * update. */
   515 {
   516     int i, length, size;
   517     unsigned char *src;
   518     char *dst;
   519     ByteArray *byteArrayPtr;
   520 
   521     byteArrayPtr = GET_BYTEARRAY(objPtr);
   522     src = byteArrayPtr->bytes;
   523     length = byteArrayPtr->used;
   524 
   525     /*
   526      * How much space will string rep need?
   527      */
   528      
   529     size = length;
   530     for (i = 0; i < length; i++) {
   531 	if ((src[i] == 0) || (src[i] > 127)) {
   532 	    size++;
   533 	}
   534     }
   535 
   536     dst = (char *) ckalloc((unsigned) (size + 1));
   537     objPtr->bytes = dst;
   538     objPtr->length = size;
   539 
   540     if (size == length) {
   541 	memcpy((VOID *) dst, (VOID *) src, (size_t) size);
   542 	dst[size] = '\0';
   543     } else {
   544 	for (i = 0; i < length; i++) {
   545 	    dst += Tcl_UniCharToUtf(src[i], dst);
   546 	}
   547 	*dst = '\0';
   548     }
   549 }
   550 
   551 /*
   552  *----------------------------------------------------------------------
   553  *
   554  * Tcl_BinaryObjCmd --
   555  *
   556  *	This procedure implements the "binary" Tcl command.
   557  *
   558  * Results:
   559  *	A standard Tcl result.
   560  *
   561  * Side effects:
   562  *	See the user documentation.
   563  *
   564  *----------------------------------------------------------------------
   565  */
   566 
   567 int
   568 Tcl_BinaryObjCmd(dummy, interp, objc, objv)
   569     ClientData dummy;		/* Not used. */
   570     Tcl_Interp *interp;		/* Current interpreter. */
   571     int objc;			/* Number of arguments. */
   572     Tcl_Obj *CONST objv[];	/* Argument objects. */
   573 {
   574     int arg;			/* Index of next argument to consume. */
   575     int value = 0;		/* Current integer value to be packed.
   576 				 * Initialized to avoid compiler warning. */
   577     char cmd;			/* Current format character. */
   578     int count;			/* Count associated with current format
   579 				 * character. */
   580     char *format;		/* Pointer to current position in format
   581 				 * string. */
   582     Tcl_Obj *resultPtr;		/* Object holding result buffer. */
   583     unsigned char *buffer;	/* Start of result buffer. */
   584     unsigned char *cursor;	/* Current position within result buffer. */
   585     unsigned char *maxPos;	/* Greatest position within result buffer that
   586 				 * cursor has visited.*/
   587     char *errorString, *errorValue, *str;
   588     int offset, size, length, index;
   589     static CONST char *options[] = { 
   590 	"format",	"scan",		NULL 
   591     };
   592     enum options { 
   593 	BINARY_FORMAT,	BINARY_SCAN
   594     };
   595 
   596     if (objc < 2) {
   597     	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
   598 	return TCL_ERROR;
   599     }
   600 
   601     if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0,
   602 	    &index) != TCL_OK) {
   603     	return TCL_ERROR;
   604     }
   605 
   606     switch ((enum options) index) {
   607 	case BINARY_FORMAT: {
   608 	    if (objc < 3) {
   609 		Tcl_WrongNumArgs(interp, 2, objv, "formatString ?arg arg ...?");
   610 		return TCL_ERROR;
   611 	    }
   612 
   613 	    /*
   614 	     * To avoid copying the data, we format the string in two passes.
   615 	     * The first pass computes the size of the output buffer.  The
   616 	     * second pass places the formatted data into the buffer.
   617 	     */
   618 
   619 	    format = Tcl_GetString(objv[2]);
   620 	    arg = 3;
   621 	    offset = 0;
   622 	    length = 0;
   623 	    while (*format != '\0') {
   624 		str = format;
   625 		if (!GetFormatSpec(&format, &cmd, &count)) {
   626 		    break;
   627 		}
   628 		switch (cmd) {
   629 		    case 'a':
   630 		    case 'A':
   631 		    case 'b':
   632 		    case 'B':
   633 		    case 'h':
   634 		    case 'H': {
   635 			/*
   636 			 * For string-type specifiers, the count corresponds
   637 			 * to the number of bytes in a single argument.
   638 			 */
   639 
   640 			if (arg >= objc) {
   641 			    goto badIndex;
   642 			}
   643 			if (count == BINARY_ALL) {
   644 			    Tcl_GetByteArrayFromObj(objv[arg], &count);
   645 			} else if (count == BINARY_NOCOUNT) {
   646 			    count = 1;
   647 			}
   648 			arg++;
   649 			if (cmd == 'a' || cmd == 'A') {
   650 			    offset += count;
   651 			} else if (cmd == 'b' || cmd == 'B') {
   652 			    offset += (count + 7) / 8;
   653 			} else {
   654 			    offset += (count + 1) / 2;
   655 			}
   656 			break;
   657 		    }
   658 		    case 'c': {
   659 			size = 1;
   660 			goto doNumbers;
   661 		    }
   662 		    case 's':
   663 		    case 'S': {
   664 			size = 2;
   665 			goto doNumbers;
   666 		    }
   667 		    case 'i':
   668 		    case 'I': {
   669 			size = 4;
   670 			goto doNumbers;
   671 		    }
   672 		    case 'w':
   673 		    case 'W': {
   674 			size = 8;
   675 			goto doNumbers;
   676 		    }
   677 		    case 'f': {
   678 			size = sizeof(float);
   679 			goto doNumbers;
   680 		    }
   681 		    case 'd': {
   682 			size = sizeof(double);
   683 			
   684 			doNumbers:
   685 			if (arg >= objc) {
   686 			    goto badIndex;
   687 			}
   688 
   689 			/*
   690 			 * For number-type specifiers, the count corresponds
   691 			 * to the number of elements in the list stored in
   692 			 * a single argument.  If no count is specified, then
   693 			 * the argument is taken as a single non-list value.
   694 			 */
   695 
   696 			if (count == BINARY_NOCOUNT) {
   697 			    arg++;
   698 			    count = 1;
   699 			} else {
   700 			    int listc;
   701 			    Tcl_Obj **listv;
   702 			    if (Tcl_ListObjGetElements(interp, objv[arg++],
   703 				    &listc, &listv) != TCL_OK) {
   704 				return TCL_ERROR;
   705 			    }
   706 			    if (count == BINARY_ALL) {
   707 				count = listc;
   708 			    } else if (count > listc) {
   709 			        Tcl_AppendResult(interp, 
   710 					"number of elements in list does not match count",
   711 					(char *) NULL);
   712 				return TCL_ERROR;
   713 			    }
   714 			}
   715 			offset += count*size;
   716 			break;
   717 		    }
   718 		    case 'x': {
   719 			if (count == BINARY_ALL) {
   720 			    Tcl_AppendResult(interp, 
   721 				    "cannot use \"*\" in format string with \"x\"",
   722 				    (char *) NULL);
   723 			    return TCL_ERROR;
   724 			} else if (count == BINARY_NOCOUNT) {
   725 			    count = 1;
   726 			}
   727 			offset += count;
   728 			break;
   729 		    }
   730 		    case 'X': {
   731 			if (count == BINARY_NOCOUNT) {
   732 			    count = 1;
   733 			}
   734 			if ((count > offset) || (count == BINARY_ALL)) {
   735 			    count = offset;
   736 			}
   737 			if (offset > length) {
   738 			    length = offset;
   739 			}
   740 			offset -= count;
   741 			break;
   742 		    }
   743 		    case '@': {
   744 			if (offset > length) {
   745 			    length = offset;
   746 			}
   747 			if (count == BINARY_ALL) {
   748 			    offset = length;
   749 			} else if (count == BINARY_NOCOUNT) {
   750 			    goto badCount;
   751 			} else {
   752 			    offset = count;
   753 			}
   754 			break;
   755 		    }
   756 		    default: {
   757 			errorString = str;
   758 			goto badField;
   759 		    }
   760 		}
   761 	    }
   762 	    if (offset > length) {
   763 		length = offset;
   764 	    }
   765 	    if (length == 0) {
   766 		return TCL_OK;
   767 	    }
   768 
   769 	    /*
   770 	     * Prepare the result object by preallocating the caclulated
   771 	     * number of bytes and filling with nulls.
   772 	     */
   773 
   774 	    resultPtr = Tcl_GetObjResult(interp);
   775 	    buffer = Tcl_SetByteArrayLength(resultPtr, length);
   776 	    memset((VOID *) buffer, 0, (size_t) length);
   777 
   778 	    /*
   779 	     * Pack the data into the result object.  Note that we can skip
   780 	     * the error checking during this pass, since we have already
   781 	     * parsed the string once.
   782 	     */
   783 
   784 	    arg = 3;
   785 	    format = Tcl_GetString(objv[2]);
   786 	    cursor = buffer;
   787 	    maxPos = cursor;
   788 	    while (*format != 0) {
   789 		if (!GetFormatSpec(&format, &cmd, &count)) {
   790 		    break;
   791 		}
   792 		if ((count == 0) && (cmd != '@')) {
   793 		    arg++;
   794 		    continue;
   795 		}
   796 		switch (cmd) {
   797 		    case 'a':
   798 		    case 'A': {
   799 			char pad = (char) (cmd == 'a' ? '\0' : ' ');
   800 			unsigned char *bytes;
   801 
   802 			bytes = Tcl_GetByteArrayFromObj(objv[arg++], &length);
   803 
   804 			if (count == BINARY_ALL) {
   805 			    count = length;
   806 			} else if (count == BINARY_NOCOUNT) {
   807 			    count = 1;
   808 			}
   809 			if (length >= count) {
   810 			    memcpy((VOID *) cursor, (VOID *) bytes,
   811 				    (size_t) count);
   812 			} else {
   813 			    memcpy((VOID *) cursor, (VOID *) bytes,
   814 				    (size_t) length);
   815 			    memset((VOID *) (cursor + length), pad,
   816 			            (size_t) (count - length));
   817 			}
   818 			cursor += count;
   819 			break;
   820 		    }
   821 		    case 'b':
   822 		    case 'B': {
   823 			unsigned char *last;
   824 			
   825 			str = Tcl_GetStringFromObj(objv[arg++], &length);
   826 			if (count == BINARY_ALL) {
   827 			    count = length;
   828 			} else if (count == BINARY_NOCOUNT) {
   829 			    count = 1;
   830 			}
   831 			last = cursor + ((count + 7) / 8);
   832 			if (count > length) {
   833 			    count = length;
   834 			}
   835 			value = 0;
   836 			errorString = "binary";
   837 			if (cmd == 'B') {
   838 			    for (offset = 0; offset < count; offset++) {
   839 				value <<= 1;
   840 				if (str[offset] == '1') {
   841 				    value |= 1;
   842 				} else if (str[offset] != '0') {
   843 				    errorValue = str;
   844 				    goto badValue;
   845 				}
   846 				if (((offset + 1) % 8) == 0) {
   847 				    *cursor++ = (unsigned char) value;
   848 				    value = 0;
   849 				}
   850 			    }
   851 			} else {
   852 			    for (offset = 0; offset < count; offset++) {
   853 				value >>= 1;
   854 				if (str[offset] == '1') {
   855 				    value |= 128;
   856 				} else if (str[offset] != '0') {
   857 				    errorValue = str;
   858 				    goto badValue;
   859 				}
   860 				if (!((offset + 1) % 8)) {
   861 				    *cursor++ = (unsigned char) value;
   862 				    value = 0;
   863 				}
   864 			    }
   865 			}
   866 			if ((offset % 8) != 0) {
   867 			    if (cmd == 'B') {
   868 				value <<= 8 - (offset % 8);
   869 			    } else {
   870 				value >>= 8 - (offset % 8);
   871 			    }
   872 			    *cursor++ = (unsigned char) value;
   873 			}
   874 			while (cursor < last) {
   875 			    *cursor++ = '\0';
   876 			}
   877 			break;
   878 		    }
   879 		    case 'h':
   880 		    case 'H': {
   881 			unsigned char *last;
   882 			int c;
   883 			
   884 			str = Tcl_GetStringFromObj(objv[arg++], &length);
   885 			if (count == BINARY_ALL) {
   886 			    count = length;
   887 			} else if (count == BINARY_NOCOUNT) {
   888 			    count = 1;
   889 			}
   890 			last = cursor + ((count + 1) / 2);
   891 			if (count > length) {
   892 			    count = length;
   893 			}
   894 			value = 0;
   895 			errorString = "hexadecimal";
   896 			if (cmd == 'H') {
   897 			    for (offset = 0; offset < count; offset++) {
   898 				value <<= 4;
   899 				if (!isxdigit(UCHAR(str[offset]))) { /* INTL: digit */
   900 				    errorValue = str;
   901 				    goto badValue;
   902 				}
   903 				c = str[offset] - '0';
   904 				if (c > 9) {
   905 				    c += ('0' - 'A') + 10;
   906 				}
   907 				if (c > 16) {
   908 				    c += ('A' - 'a');
   909 				}
   910 				value |= (c & 0xf);
   911 				if (offset % 2) {
   912 				    *cursor++ = (char) value;
   913 				    value = 0;
   914 				}
   915 			    }
   916 			} else {
   917 			    for (offset = 0; offset < count; offset++) {
   918 				value >>= 4;
   919 
   920 				if (!isxdigit(UCHAR(str[offset]))) { /* INTL: digit */
   921 				    errorValue = str;
   922 				    goto badValue;
   923 				}
   924 				c = str[offset] - '0';
   925 				if (c > 9) {
   926 				    c += ('0' - 'A') + 10;
   927 				}
   928 				if (c > 16) {
   929 				    c += ('A' - 'a');
   930 				}
   931 				value |= ((c << 4) & 0xf0);
   932 				if (offset % 2) {
   933 				    *cursor++ = (unsigned char)(value & 0xff);
   934 				    value = 0;
   935 				}
   936 			    }
   937 			}
   938 			if (offset % 2) {
   939 			    if (cmd == 'H') {
   940 				value <<= 4;
   941 			    } else {
   942 				value >>= 4;
   943 			    }
   944 			    *cursor++ = (unsigned char) value;
   945 			}
   946 
   947 			while (cursor < last) {
   948 			    *cursor++ = '\0';
   949 			}
   950 			break;
   951 		    }
   952 		    case 'c':
   953 		    case 's':
   954 		    case 'S':
   955 		    case 'i':
   956 		    case 'I':
   957 		    case 'w':
   958 		    case 'W':
   959 		    case 'd':
   960 		    case 'f': {
   961 			int listc, i;
   962 			Tcl_Obj **listv;
   963 
   964 			if (count == BINARY_NOCOUNT) {
   965 			    /*
   966 			     * Note that we are casting away the const-ness of
   967 			     * objv, but this is safe since we aren't going to
   968 			     * modify the array.
   969 			     */
   970 
   971 			    listv = (Tcl_Obj**)(objv + arg);
   972 			    listc = 1;
   973 			    count = 1;
   974 			} else {
   975 			    Tcl_ListObjGetElements(interp, objv[arg],
   976 				    &listc, &listv);
   977 			    if (count == BINARY_ALL) {
   978 				count = listc;
   979 			    }
   980 			}
   981 			arg++;
   982 			for (i = 0; i < count; i++) {
   983 			    if (FormatNumber(interp, cmd, listv[i], &cursor)
   984 				    != TCL_OK) {
   985 				return TCL_ERROR;
   986 			    }
   987 			}
   988 			break;
   989 		    }
   990 		    case 'x': {
   991 			if (count == BINARY_NOCOUNT) {
   992 			    count = 1;
   993 			}
   994 			memset(cursor, 0, (size_t) count);
   995 			cursor += count;
   996 			break;
   997 		    }
   998 		    case 'X': {
   999 			if (cursor > maxPos) {
  1000 			    maxPos = cursor;
  1001 			}
  1002 			if (count == BINARY_NOCOUNT) {
  1003 			    count = 1;
  1004 			}
  1005 			if ((count == BINARY_ALL)
  1006 				|| (count > (cursor - buffer))) {
  1007 			    cursor = buffer;
  1008 			} else {
  1009 			    cursor -= count;
  1010 			}
  1011 			break;
  1012 		    }
  1013 		    case '@': {
  1014 			if (cursor > maxPos) {
  1015 			    maxPos = cursor;
  1016 			}
  1017 			if (count == BINARY_ALL) {
  1018 			    cursor = maxPos;
  1019 			} else {
  1020 			    cursor = buffer + count;
  1021 			}
  1022 			break;
  1023 		    }
  1024 		}
  1025 	    }
  1026 	    break;
  1027 	}
  1028 	case BINARY_SCAN: {
  1029 	    int i;
  1030 	    Tcl_Obj *valuePtr, *elementPtr;
  1031 	    Tcl_HashTable numberCacheHash;
  1032 	    Tcl_HashTable *numberCachePtr;
  1033 
  1034 	    if (objc < 4) {
  1035 		Tcl_WrongNumArgs(interp, 2, objv,
  1036 			"value formatString ?varName varName ...?");
  1037 		return TCL_ERROR;
  1038 	    }
  1039 	    numberCachePtr = &numberCacheHash;
  1040 	    Tcl_InitHashTable(numberCachePtr, TCL_ONE_WORD_KEYS);
  1041 	    buffer = Tcl_GetByteArrayFromObj(objv[2], &length);
  1042 	    format = Tcl_GetString(objv[3]);
  1043 	    cursor = buffer;
  1044 	    arg = 4;
  1045 	    offset = 0;
  1046 	    while (*format != '\0') {
  1047 		str = format;
  1048 		if (!GetFormatSpec(&format, &cmd, &count)) {
  1049 		    goto done;
  1050 		}
  1051 		switch (cmd) {
  1052 		    case 'a':
  1053 		    case 'A': {
  1054 			unsigned char *src;
  1055 
  1056 			if (arg >= objc) {
  1057 			    DeleteScanNumberCache(numberCachePtr);
  1058 			    goto badIndex;
  1059 			}
  1060 			if (count == BINARY_ALL) {
  1061 			    count = length - offset;
  1062 			} else {
  1063 			    if (count == BINARY_NOCOUNT) {
  1064 				count = 1;
  1065 			    }
  1066 			    if (count > (length - offset)) {
  1067 				goto done;
  1068 			    }
  1069 			}
  1070 
  1071 			src = buffer + offset;
  1072 			size = count;
  1073 
  1074 			/*
  1075 			 * Trim trailing nulls and spaces, if necessary.
  1076 			 */
  1077 
  1078 			if (cmd == 'A') {
  1079 			    while (size > 0) {
  1080 				if (src[size-1] != '\0' && src[size-1] != ' ') {
  1081 				    break;
  1082 				}
  1083 				size--;
  1084 			    }
  1085 			}
  1086 			valuePtr = Tcl_NewByteArrayObj(src, size);
  1087 			Tcl_IncrRefCount(valuePtr);
  1088 			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
  1089 				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
  1090 			Tcl_DecrRefCount(valuePtr);
  1091 			arg++;
  1092 			if (resultPtr == NULL) {
  1093 			    DeleteScanNumberCache(numberCachePtr);
  1094 			    return TCL_ERROR;
  1095 			}
  1096 			offset += count;
  1097 			break;
  1098 		    }
  1099 		    case 'b':
  1100 		    case 'B': {
  1101 			unsigned char *src;
  1102 			char *dest;
  1103 
  1104 			if (arg >= objc) {
  1105 			    DeleteScanNumberCache(numberCachePtr);
  1106 			    goto badIndex;
  1107 			}
  1108 			if (count == BINARY_ALL) {
  1109 			    count = (length - offset) * 8;
  1110 			} else {
  1111 			    if (count == BINARY_NOCOUNT) {
  1112 				count = 1;
  1113 			    }
  1114 			    if (count > (length - offset) * 8) {
  1115 				goto done;
  1116 			    }
  1117 			}
  1118 			src = buffer + offset;
  1119 			valuePtr = Tcl_NewObj();
  1120 			Tcl_SetObjLength(valuePtr, count);
  1121 			dest = Tcl_GetString(valuePtr);
  1122 
  1123 			if (cmd == 'b') {
  1124 			    for (i = 0; i < count; i++) {
  1125 				if (i % 8) {
  1126 				    value >>= 1;
  1127 				} else {
  1128 				    value = *src++;
  1129 				}
  1130 				*dest++ = (char) ((value & 1) ? '1' : '0');
  1131 			    }
  1132 			} else {
  1133 			    for (i = 0; i < count; i++) {
  1134 				if (i % 8) {
  1135 				    value <<= 1;
  1136 				} else {
  1137 				    value = *src++;
  1138 				}
  1139 				*dest++ = (char) ((value & 0x80) ? '1' : '0');
  1140 			    }
  1141 			}
  1142 
  1143 			Tcl_IncrRefCount(valuePtr);			
  1144 			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
  1145 				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
  1146 			Tcl_DecrRefCount(valuePtr);
  1147 			arg++;
  1148 			if (resultPtr == NULL) {
  1149 			    DeleteScanNumberCache(numberCachePtr);
  1150 			    return TCL_ERROR;
  1151 			}
  1152 			offset += (count + 7 ) / 8;
  1153 			break;
  1154 		    }
  1155 		    case 'h':
  1156 		    case 'H': {
  1157 			char *dest;
  1158 			unsigned char *src;
  1159 			int i;
  1160 			static char hexdigit[] = "0123456789abcdef";
  1161 
  1162 			if (arg >= objc) {
  1163 			    DeleteScanNumberCache(numberCachePtr);
  1164 			    goto badIndex;
  1165 			}
  1166 			if (count == BINARY_ALL) {
  1167 			    count = (length - offset)*2;
  1168 			} else {
  1169 			    if (count == BINARY_NOCOUNT) {
  1170 				count = 1;
  1171 			    }
  1172 			    if (count > (length - offset)*2) {
  1173 				goto done;
  1174 			    }
  1175 			}
  1176 			src = buffer + offset;
  1177 			valuePtr = Tcl_NewObj();
  1178 			Tcl_SetObjLength(valuePtr, count);
  1179 			dest = Tcl_GetString(valuePtr);
  1180 
  1181 			if (cmd == 'h') {
  1182 			    for (i = 0; i < count; i++) {
  1183 				if (i % 2) {
  1184 				    value >>= 4;
  1185 				} else {
  1186 				    value = *src++;
  1187 				}
  1188 				*dest++ = hexdigit[value & 0xf];
  1189 			    }
  1190 			} else {
  1191 			    for (i = 0; i < count; i++) {
  1192 				if (i % 2) {
  1193 				    value <<= 4;
  1194 				} else {
  1195 				    value = *src++;
  1196 				}
  1197 				*dest++ = hexdigit[(value >> 4) & 0xf];
  1198 			    }
  1199 			}
  1200 			
  1201 			Tcl_IncrRefCount(valuePtr);
  1202 			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
  1203 				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
  1204 			Tcl_DecrRefCount(valuePtr);
  1205 			arg++;
  1206 			if (resultPtr == NULL) {
  1207 			    DeleteScanNumberCache(numberCachePtr);
  1208 			    return TCL_ERROR;
  1209 			}
  1210 			offset += (count + 1) / 2;
  1211 			break;
  1212 		    }
  1213 		    case 'c': {
  1214 			size = 1;
  1215 			goto scanNumber;
  1216 		    }
  1217 		    case 's':
  1218 		    case 'S': {
  1219 			size = 2;
  1220 			goto scanNumber;
  1221 		    }
  1222 		    case 'i':
  1223 		    case 'I': {
  1224 			size = 4;
  1225 			goto scanNumber;
  1226 		    }
  1227 		    case 'w':
  1228 		    case 'W': {
  1229 			size = 8;
  1230 			goto scanNumber;
  1231 		    }
  1232 		    case 'f': {
  1233 			size = sizeof(float);
  1234 			goto scanNumber;
  1235 		    }
  1236 		    case 'd': {
  1237 			unsigned char *src;
  1238 
  1239 			size = sizeof(double);
  1240 			/* fall through */
  1241 			
  1242 			scanNumber:
  1243 			if (arg >= objc) {
  1244 			    DeleteScanNumberCache(numberCachePtr);
  1245 			    goto badIndex;
  1246 			}
  1247 			if (count == BINARY_NOCOUNT) {
  1248 			    if ((length - offset) < size) {
  1249 				goto done;
  1250 			    }
  1251 			    valuePtr = ScanNumber(buffer+offset, cmd,
  1252 				    &numberCachePtr);
  1253 			    offset += size;
  1254 			} else {
  1255 			    if (count == BINARY_ALL) {
  1256 				count = (length - offset) / size;
  1257 			    }
  1258 			    if ((length - offset) < (count * size)) {
  1259 				goto done;
  1260 			    }
  1261 			    valuePtr = Tcl_NewObj();
  1262 			    src = buffer+offset;
  1263 			    for (i = 0; i < count; i++) {
  1264 				elementPtr = ScanNumber(src, cmd,
  1265 					&numberCachePtr);
  1266 				src += size;
  1267 				Tcl_ListObjAppendElement(NULL, valuePtr,
  1268 					elementPtr);
  1269 			    }
  1270 			    offset += count*size;
  1271 			}
  1272 
  1273 			Tcl_IncrRefCount(valuePtr); 
  1274 			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
  1275 				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
  1276 			Tcl_DecrRefCount(valuePtr);
  1277 			arg++;
  1278 			if (resultPtr == NULL) {
  1279 			    DeleteScanNumberCache(numberCachePtr);
  1280 			    return TCL_ERROR;
  1281 			}
  1282 			break;
  1283 		    }
  1284 		    case 'x': {
  1285 			if (count == BINARY_NOCOUNT) {
  1286 			    count = 1;
  1287 			}
  1288 			if ((count == BINARY_ALL)
  1289 				|| (count > (length - offset))) {
  1290 			    offset = length;
  1291 			} else {
  1292 			    offset += count;
  1293 			}
  1294 			break;
  1295 		    }
  1296 		    case 'X': {
  1297 			if (count == BINARY_NOCOUNT) {
  1298 			    count = 1;
  1299 			}
  1300 			if ((count == BINARY_ALL) || (count > offset)) {
  1301 			    offset = 0;
  1302 			} else {
  1303 			    offset -= count;
  1304 			}
  1305 			break;
  1306 		    }
  1307 		    case '@': {
  1308 			if (count == BINARY_NOCOUNT) {
  1309 			    DeleteScanNumberCache(numberCachePtr);
  1310 			    goto badCount;
  1311 			}
  1312 			if ((count == BINARY_ALL) || (count > length)) {
  1313 			    offset = length;
  1314 			} else {
  1315 			    offset = count;
  1316 			}
  1317 			break;
  1318 		    }
  1319 		    default: {
  1320 			DeleteScanNumberCache(numberCachePtr);
  1321 			errorString = str;
  1322 			goto badField;
  1323 		    }
  1324 		}
  1325 	    }
  1326 
  1327 	    /*
  1328 	     * Set the result to the last position of the cursor.
  1329 	     */
  1330 
  1331 	    done:
  1332 	    Tcl_ResetResult(interp);
  1333 	    Tcl_SetLongObj(Tcl_GetObjResult(interp), arg - 4);
  1334 	    DeleteScanNumberCache(numberCachePtr);
  1335 	    break;
  1336 	}
  1337     }
  1338     return TCL_OK;
  1339 
  1340     badValue:
  1341     Tcl_ResetResult(interp);
  1342     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "expected ", errorString,
  1343 	    " string but got \"", errorValue, "\" instead", NULL);
  1344     return TCL_ERROR;
  1345 
  1346     badCount:
  1347     errorString = "missing count for \"@\" field specifier";
  1348     goto error;
  1349 
  1350     badIndex:
  1351     errorString = "not enough arguments for all format specifiers";
  1352     goto error;
  1353 
  1354     badField:
  1355     {
  1356 	Tcl_UniChar ch;
  1357 	char buf[TCL_UTF_MAX + 1];
  1358 
  1359 	Tcl_UtfToUniChar(errorString, &ch);
  1360 	buf[Tcl_UniCharToUtf(ch, buf)] = '\0';
  1361 	Tcl_AppendResult(interp, "bad field specifier \"", buf, "\"", NULL);
  1362 	return TCL_ERROR;
  1363     }
  1364 
  1365     error:
  1366     Tcl_AppendResult(interp, errorString, NULL);
  1367     return TCL_ERROR;
  1368 }
  1369 
  1370 /*
  1371  *----------------------------------------------------------------------
  1372  *
  1373  * GetFormatSpec --
  1374  *
  1375  *	This function parses the format strings used in the binary
  1376  *	format and scan commands.
  1377  *
  1378  * Results:
  1379  *	Moves the formatPtr to the start of the next command. Returns
  1380  *	the current command character and count in cmdPtr and countPtr.
  1381  *	The count is set to BINARY_ALL if the count character was '*'
  1382  *	or BINARY_NOCOUNT if no count was specified.  Returns 1 on
  1383  *	success, or 0 if the string did not have a format specifier.
  1384  *
  1385  * Side effects:
  1386  *	None.
  1387  *
  1388  *----------------------------------------------------------------------
  1389  */
  1390 
  1391 static int
  1392 GetFormatSpec(formatPtr, cmdPtr, countPtr)
  1393     char **formatPtr;		/* Pointer to format string. */
  1394     char *cmdPtr;		/* Pointer to location of command char. */
  1395     int *countPtr;		/* Pointer to repeat count value. */
  1396 {
  1397     /*
  1398      * Skip any leading blanks.
  1399      */
  1400 
  1401     while (**formatPtr == ' ') {
  1402 	(*formatPtr)++;
  1403     }
  1404 
  1405     /*
  1406      * The string was empty, except for whitespace, so fail.
  1407      */
  1408 
  1409     if (!(**formatPtr)) {
  1410 	return 0;
  1411     }
  1412 
  1413     /*
  1414      * Extract the command character and any trailing digits or '*'.
  1415      */
  1416 
  1417     *cmdPtr = **formatPtr;
  1418     (*formatPtr)++;
  1419     if (**formatPtr == '*') {
  1420 	(*formatPtr)++;
  1421 	(*countPtr) = BINARY_ALL;
  1422     } else if (isdigit(UCHAR(**formatPtr))) { /* INTL: digit */
  1423 	(*countPtr) = strtoul(*formatPtr, formatPtr, 10);
  1424     } else {
  1425 	(*countPtr) = BINARY_NOCOUNT;
  1426     }
  1427     return 1;
  1428 }
  1429 
  1430 /*
  1431  *----------------------------------------------------------------------
  1432  *
  1433  * FormatNumber --
  1434  *
  1435  *	This routine is called by Tcl_BinaryObjCmd to format a number
  1436  *	into a location pointed at by cursor.
  1437  *
  1438  * Results:
  1439  *	 A standard Tcl result.
  1440  *
  1441  * Side effects:
  1442  *	Moves the cursor to the next location to be written into.
  1443  *
  1444  *----------------------------------------------------------------------
  1445  */
  1446 
  1447 static int
  1448 FormatNumber(interp, type, src, cursorPtr)
  1449     Tcl_Interp *interp;		/* Current interpreter, used to report
  1450 				 * errors. */
  1451     int type;			/* Type of number to format. */
  1452     Tcl_Obj *src;		/* Number to format. */
  1453     unsigned char **cursorPtr;	/* Pointer to index into destination buffer. */
  1454 {
  1455     long value;
  1456     double dvalue;
  1457     Tcl_WideInt wvalue;
  1458 
  1459     switch (type) {
  1460     case 'd':
  1461     case 'f':
  1462 	/*
  1463 	 * For floating point types, we need to copy the data using
  1464 	 * memcpy to avoid alignment issues.
  1465 	 */
  1466 
  1467 	if (Tcl_GetDoubleFromObj(interp, src, &dvalue) != TCL_OK) {
  1468 	    return TCL_ERROR;
  1469 	}
  1470 	if (type == 'd') {
  1471 	    /*
  1472 	     * Can't just memcpy() here. [Bug 1116542]
  1473 	     */
  1474 
  1475 	    CopyNumber(&dvalue, *cursorPtr, sizeof(double));
  1476 	    *cursorPtr += sizeof(double);
  1477 	} else {
  1478 	    float fvalue;
  1479 
  1480 	    /*
  1481 	     * Because some compilers will generate floating point exceptions
  1482 	     * on an overflow cast (e.g. Borland), we restrict the values
  1483 	     * to the valid range for float.
  1484 	     */
  1485 
  1486 	    if (fabs(dvalue) > (double)FLT_MAX) {
  1487 		fvalue = (dvalue >= 0.0) ? FLT_MAX : -FLT_MAX;
  1488 	    } else {
  1489 		fvalue = (float) dvalue;
  1490 	    }
  1491 	    memcpy((VOID *) *cursorPtr, (VOID *) &fvalue, sizeof(float));
  1492 	    *cursorPtr += sizeof(float);
  1493 	}
  1494 	return TCL_OK;
  1495 
  1496 	/*
  1497 	 * Next cases separate from other integer cases because we
  1498 	 * need a different API to get a wide.
  1499 	 */
  1500     case 'w':
  1501     case 'W':
  1502 	if (Tcl_GetWideIntFromObj(interp, src, &wvalue) != TCL_OK) {
  1503 	    return TCL_ERROR;
  1504 	}
  1505 	if (type == 'w') {
  1506 	    *(*cursorPtr)++ = (unsigned char) wvalue;
  1507 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 8);
  1508 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 16);
  1509 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 24);
  1510 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 32);
  1511 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 40);
  1512 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 48);
  1513 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 56);
  1514 	} else {
  1515 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 56);
  1516 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 48);
  1517 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 40);
  1518 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 32);
  1519 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 24);
  1520 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 16);
  1521 	    *(*cursorPtr)++ = (unsigned char) (wvalue >> 8);
  1522 	    *(*cursorPtr)++ = (unsigned char) wvalue;
  1523 	}
  1524 	return TCL_OK;
  1525     default:
  1526 	if (Tcl_GetLongFromObj(interp, src, &value) != TCL_OK) {
  1527 	    return TCL_ERROR;
  1528 	}
  1529 	if (type == 'c') {
  1530 	    *(*cursorPtr)++ = (unsigned char) value;
  1531 	} else if (type == 's') {
  1532 	    *(*cursorPtr)++ = (unsigned char) value;
  1533 	    *(*cursorPtr)++ = (unsigned char) (value >> 8);
  1534 	} else if (type == 'S') {
  1535 	    *(*cursorPtr)++ = (unsigned char) (value >> 8);
  1536 	    *(*cursorPtr)++ = (unsigned char) value;
  1537 	} else if (type == 'i') {
  1538 	    *(*cursorPtr)++ = (unsigned char) value;
  1539 	    *(*cursorPtr)++ = (unsigned char) (value >> 8);
  1540 	    *(*cursorPtr)++ = (unsigned char) (value >> 16);
  1541 	    *(*cursorPtr)++ = (unsigned char) (value >> 24);
  1542 	} else if (type == 'I') {
  1543 	    *(*cursorPtr)++ = (unsigned char) (value >> 24);
  1544 	    *(*cursorPtr)++ = (unsigned char) (value >> 16);
  1545 	    *(*cursorPtr)++ = (unsigned char) (value >> 8);
  1546 	    *(*cursorPtr)++ = (unsigned char) value;
  1547 	}
  1548 	return TCL_OK;
  1549     }
  1550 }
  1551 
  1552 /* Ugly workaround for old and broken compiler! */
  1553 static void
  1554 CopyNumber(from, to, length)
  1555     CONST VOID *from;
  1556     VOID *to;
  1557     unsigned int length;
  1558 {
  1559     memcpy(to, from, length);
  1560 }
  1561 
  1562 /*
  1563  *----------------------------------------------------------------------
  1564  *
  1565  * ScanNumber --
  1566  *
  1567  *	This routine is called by Tcl_BinaryObjCmd to scan a number
  1568  *	out of a buffer.
  1569  *
  1570  * Results:
  1571  *	Returns a newly created object containing the scanned number.
  1572  *	This object has a ref count of zero.
  1573  *
  1574  * Side effects:
  1575  *	Might reuse an object in the number cache, place a new object
  1576  *	in the cache, or delete the cache and set the reference to
  1577  *	it (itself passed in by reference) to NULL.
  1578  *
  1579  *----------------------------------------------------------------------
  1580  */
  1581 
  1582 static Tcl_Obj *
  1583 ScanNumber(buffer, type, numberCachePtrPtr)
  1584     unsigned char *buffer;	/* Buffer to scan number from. */
  1585     int type;			/* Format character from "binary scan" */
  1586     Tcl_HashTable **numberCachePtrPtr;
  1587 				/* Place to look for cache of scanned
  1588 				 * value objects, or NULL if too many
  1589 				 * different numbers have been scanned. */
  1590 {
  1591     long value;
  1592     Tcl_WideUInt uwvalue;
  1593 
  1594     /*
  1595      * We cannot rely on the compiler to properly sign extend integer values
  1596      * when we cast from smaller values to larger values because we don't know
  1597      * the exact size of the integer types.  So, we have to handle sign
  1598      * extension explicitly by checking the high bit and padding with 1's as
  1599      * needed.
  1600      */
  1601 
  1602     switch (type) {
  1603 	case 'c':
  1604 	    /*
  1605 	     * Characters need special handling.  We want to produce a
  1606 	     * signed result, but on some platforms (such as AIX) chars
  1607 	     * are unsigned.  To deal with this, check for a value that
  1608 	     * should be negative but isn't.
  1609 	     */
  1610 
  1611 	    value = buffer[0];
  1612 	    if (value & 0x80) {
  1613 		value |= -0x100;
  1614 	    }
  1615 	    goto returnNumericObject;
  1616 
  1617 	case 's':
  1618 	    value = (long) (buffer[0] + (buffer[1] << 8));
  1619 	    goto shortValue;
  1620 	case 'S':
  1621 	    value = (long) (buffer[1] + (buffer[0] << 8));
  1622 	    shortValue:
  1623 	    if (value & 0x8000) {
  1624 		value |= -0x10000;
  1625 	    }
  1626 	    goto returnNumericObject;
  1627 
  1628 	case 'i':
  1629 	    value = (long) (buffer[0] 
  1630 		    + (buffer[1] << 8)
  1631 		    + (buffer[2] << 16)
  1632 		    + (buffer[3] << 24));
  1633 	    goto intValue;
  1634 	case 'I':
  1635 	    value = (long) (buffer[3]
  1636 		    + (buffer[2] << 8)
  1637 		    + (buffer[1] << 16)
  1638 		    + (buffer[0] << 24));
  1639 	    intValue:
  1640 	    /*
  1641 	     * Check to see if the value was sign extended properly on
  1642 	     * systems where an int is more than 32-bits.
  1643 	     */
  1644 
  1645 	    if ((value & (((unsigned int)1)<<31)) && (value > 0)) {
  1646 		value -= (((unsigned int)1)<<31);
  1647 		value -= (((unsigned int)1)<<31);
  1648 	    }
  1649 	    returnNumericObject:
  1650 	    if (*numberCachePtrPtr == NULL) {
  1651 		return Tcl_NewLongObj(value);
  1652 	    } else {
  1653 		register Tcl_HashTable *tablePtr = *numberCachePtrPtr;
  1654 		register Tcl_HashEntry *hPtr;
  1655 		int isNew;
  1656 
  1657 		hPtr = Tcl_CreateHashEntry(tablePtr, (char *)value, &isNew);
  1658 		if (!isNew) {
  1659 		    return (Tcl_Obj *) Tcl_GetHashValue(hPtr);
  1660 		}
  1661 		if (tablePtr->numEntries > BINARY_SCAN_MAX_CACHE) {
  1662 		    /*
  1663 		     * We've overflowed the cache!  Someone's parsing
  1664 		     * a LOT of varied binary data in a single call!
  1665 		     * Bail out by switching back to the old behaviour
  1666 		     * for the rest of the scan.
  1667 		     *
  1668 		     * Note that anyone just using the 'c' conversion
  1669 		     * (for bytes) cannot trigger this.
  1670 		     */
  1671 		    DeleteScanNumberCache(tablePtr);
  1672 		    *numberCachePtrPtr = NULL;
  1673 		    return Tcl_NewLongObj(value);
  1674 		} else {
  1675 		    register Tcl_Obj *objPtr = Tcl_NewLongObj(value);
  1676 
  1677 		    Tcl_IncrRefCount(objPtr);
  1678 		    Tcl_SetHashValue(hPtr, (ClientData) objPtr);
  1679 		    return objPtr;
  1680 		}
  1681 	    }
  1682 
  1683 	    /*
  1684 	     * Do not cache wide values; they are already too large to
  1685 	     * use as keys.
  1686 	     */
  1687 	case 'w':
  1688 	    uwvalue =  ((Tcl_WideUInt) buffer[0])
  1689 		    | (((Tcl_WideUInt) buffer[1]) << 8)
  1690 		    | (((Tcl_WideUInt) buffer[2]) << 16)
  1691 		    | (((Tcl_WideUInt) buffer[3]) << 24)
  1692 		    | (((Tcl_WideUInt) buffer[4]) << 32)
  1693 		    | (((Tcl_WideUInt) buffer[5]) << 40)
  1694 		    | (((Tcl_WideUInt) buffer[6]) << 48)
  1695 		    | (((Tcl_WideUInt) buffer[7]) << 56);
  1696 	    return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue);
  1697 	case 'W':
  1698 	    uwvalue =  ((Tcl_WideUInt) buffer[7])
  1699 		    | (((Tcl_WideUInt) buffer[6]) << 8)
  1700 		    | (((Tcl_WideUInt) buffer[5]) << 16)
  1701 		    | (((Tcl_WideUInt) buffer[4]) << 24)
  1702 		    | (((Tcl_WideUInt) buffer[3]) << 32)
  1703 		    | (((Tcl_WideUInt) buffer[2]) << 40)
  1704 		    | (((Tcl_WideUInt) buffer[1]) << 48)
  1705 		    | (((Tcl_WideUInt) buffer[0]) << 56);
  1706 	    return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue);
  1707 
  1708 	    /*
  1709 	     * Do not cache double values; they are already too large
  1710 	     * to use as keys and the values stored are utterly
  1711 	     * incompatible too.
  1712 	     */
  1713 	case 'f': {
  1714 	    float fvalue;
  1715 	    memcpy((VOID *) &fvalue, (VOID *) buffer, sizeof(float));
  1716 	    return Tcl_NewDoubleObj(fvalue);
  1717 	}
  1718 	case 'd': {
  1719 	    double dvalue;
  1720 	    memcpy((VOID *) &dvalue, (VOID *) buffer, sizeof(double));
  1721 	    return Tcl_NewDoubleObj(dvalue);
  1722 	}
  1723     }
  1724     return NULL;
  1725 }
  1726 
  1727 /*
  1728  *----------------------------------------------------------------------
  1729  *
  1730  * DeleteScanNumberCache --
  1731  * 
  1732  *	Deletes the hash table acting as a scan number cache.
  1733  *
  1734  * Results:
  1735  *	None
  1736  *
  1737  * Side effects:
  1738  *	Decrements the reference counts of the objects in the cache.
  1739  *
  1740  *----------------------------------------------------------------------
  1741  */
  1742 
  1743 static void
  1744 DeleteScanNumberCache(numberCachePtr)
  1745     Tcl_HashTable *numberCachePtr;	/* Pointer to the hash table, or
  1746 					 * NULL (when the cache has already
  1747 					 * been deleted due to overflow.) */
  1748 {
  1749     Tcl_HashEntry *hEntry;
  1750     Tcl_HashSearch search;
  1751 
  1752     if (numberCachePtr == NULL) {
  1753 	return;
  1754     }
  1755 
  1756     hEntry = Tcl_FirstHashEntry(numberCachePtr, &search);
  1757     while (hEntry != NULL) {
  1758 	register Tcl_Obj *value = (Tcl_Obj *) Tcl_GetHashValue(hEntry);
  1759 
  1760 	if (value != NULL) {
  1761 	    Tcl_DecrRefCount(value);
  1762 	}
  1763 	hEntry = Tcl_NextHashEntry(&search);
  1764     }
  1765     Tcl_DeleteHashTable(numberCachePtr);
  1766 }