diff options
author | rjohnson <rjohnson> | 1998-03-26 14:45:59 (GMT) |
---|---|---|
committer | rjohnson <rjohnson> | 1998-03-26 14:45:59 (GMT) |
commit | 2b5738da524e944cda39e24c0a87b745a43bd8c3 (patch) | |
tree | 6e8c9473978f6dab66c601e911721a7bd9d70b1b /generic/tclBinary.c | |
parent | c6a259aeeca4814a97cf6694814c63e74e4e18fa (diff) | |
download | tcl-2b5738da524e944cda39e24c0a87b745a43bd8c3.zip tcl-2b5738da524e944cda39e24c0a87b745a43bd8c3.tar.gz tcl-2b5738da524e944cda39e24c0a87b745a43bd8c3.tar.bz2 |
Initial revision
Diffstat (limited to 'generic/tclBinary.c')
-rw-r--r-- | generic/tclBinary.c | 1013 |
1 files changed, 1013 insertions, 0 deletions
diff --git a/generic/tclBinary.c b/generic/tclBinary.c new file mode 100644 index 0000000..e15fe4c --- /dev/null +++ b/generic/tclBinary.c @@ -0,0 +1,1013 @@ +/* + * tclBinary.c -- + * + * This file contains the implementation of the "binary" Tcl built-in + * command . + * + * Copyright (c) 1997 by Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tclBinary.c 1.26 97/11/05 13:02:05 + */ + +#include <math.h> +#include "tclInt.h" +#include "tclPort.h" + +/* + * The following constants are used by GetFormatSpec to indicate various + * special conditions in the parsing of a format specifier. + */ + +#define BINARY_ALL -1 /* Use all elements in the argument. */ +#define BINARY_NOCOUNT -2 /* No count was specified in format. */ + +/* + * Prototypes for local procedures defined in this file: + */ + +static int GetFormatSpec _ANSI_ARGS_((char **formatPtr, + char *cmdPtr, int *countPtr)); +static int FormatNumber _ANSI_ARGS_((Tcl_Interp *interp, int type, + Tcl_Obj *src, char **cursorPtr)); +static Tcl_Obj * ScanNumber _ANSI_ARGS_((char *buffer, int type)); + +/* + *---------------------------------------------------------------------- + * + * Tcl_BinaryObjCmd -- + * + * This procedure implements the "binary" Tcl command. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_BinaryObjCmd(dummy, interp, objc, objv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + int arg; /* Index of next argument to consume. */ + int value = 0; /* Current integer value to be packed. + * Initialized to avoid compiler warning. */ + char cmd; /* Current format character. */ + int count; /* Count associated with current format + * character. */ + char *format; /* Pointer to current position in format + * string. */ + char *cursor; /* Current position within result buffer. */ + char *maxPos; /* Greatest position within result buffer that + * cursor has visited.*/ + char *buffer; /* Start of data buffer. */ + char *errorString, *errorValue, *str; + int offset, size, length; + Tcl_Obj *resultPtr; + + static char *subCmds[] = { "format", "scan", (char *) NULL }; + enum { BinaryFormat, BinaryScan } index; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[1], subCmds, "option", 0, + (int *) &index) != TCL_OK) { + return TCL_ERROR; + } + + switch (index) { + case BinaryFormat: + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "formatString ?arg arg ...?"); + return TCL_ERROR; + } + /* + * To avoid copying the data, we format the string in two passes. + * The first pass computes the size of the output buffer. The + * second pass places the formatted data into the buffer. + */ + + format = Tcl_GetStringFromObj(objv[2], NULL); + arg = 3; + offset = length = 0; + while (*format != 0) { + if (!GetFormatSpec(&format, &cmd, &count)) { + break; + } + switch (cmd) { + case 'a': + case 'A': + case 'b': + case 'B': + case 'h': + case 'H': + /* + * For string-type specifiers, the count corresponds + * to the number of characters in a single argument. + */ + + if (arg >= objc) { + goto badIndex; + } + if (count == BINARY_ALL) { + (void)Tcl_GetStringFromObj(objv[arg], &count); + } else if (count == BINARY_NOCOUNT) { + count = 1; + } + arg++; + if (cmd == 'a' || cmd == 'A') { + offset += count; + } else if (cmd == 'b' || cmd == 'B') { + offset += (count + 7) / 8; + } else { + offset += (count + 1) / 2; + } + break; + + case 'c': + size = 1; + goto doNumbers; + case 's': + case 'S': + size = 2; + goto doNumbers; + case 'i': + case 'I': + size = 4; + goto doNumbers; + case 'f': + size = sizeof(float); + goto doNumbers; + case 'd': + size = sizeof(double); + doNumbers: + if (arg >= objc) { + goto badIndex; + } + + /* + * For number-type specifiers, the count corresponds + * to the number of elements in the list stored in + * a single argument. If no count is specified, then + * the argument is taken as a single non-list value. + */ + + if (count == BINARY_NOCOUNT) { + arg++; + count = 1; + } else { + int listc; + Tcl_Obj **listv; + if (Tcl_ListObjGetElements(interp, objv[arg++], + &listc, &listv) != TCL_OK) { + return TCL_ERROR; + } + if (count == BINARY_ALL) { + count = listc; + } else if (count > listc) { + errorString = "number of elements in list does not match count"; + goto error; + } + } + offset += count*size; + break; + + case 'x': + if (count == BINARY_ALL) { + errorString = "cannot use \"*\" in format string with \"x\""; + goto error; + } else if (count == BINARY_NOCOUNT) { + count = 1; + } + offset += count; + break; + case 'X': + if (count == BINARY_NOCOUNT) { + count = 1; + } + if ((count > offset) || (count == BINARY_ALL)) { + count = offset; + } + if (offset > length) { + length = offset; + } + offset -= count; + break; + case '@': + if (offset > length) { + length = offset; + } + if (count == BINARY_ALL) { + offset = length; + } else if (count == BINARY_NOCOUNT) { + goto badCount; + } else { + offset = count; + } + break; + default: { + char buf[2]; + + Tcl_ResetResult(interp); + buf[0] = cmd; + buf[1] = '\0'; + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "bad field specifier \"", buf, "\"", NULL); + return TCL_ERROR; + } + } + } + if (offset > length) { + length = offset; + } + if (length == 0) { + return TCL_OK; + } + + /* + * Prepare the result object by preallocating the caclulated + * number of bytes and filling with nulls. + */ + + resultPtr = Tcl_GetObjResult(interp); + Tcl_SetObjLength(resultPtr, length); + buffer = Tcl_GetStringFromObj(resultPtr, NULL); + memset(buffer, 0, (size_t) length); + + /* + * Pack the data into the result object. Note that we can skip + * the error checking during this pass, since we have already + * parsed the string once. + */ + + arg = 3; + format = Tcl_GetStringFromObj(objv[2], NULL); + cursor = buffer; + maxPos = cursor; + while (*format != 0) { + if (!GetFormatSpec(&format, &cmd, &count)) { + break; + } + if ((count == 0) && (cmd != '@')) { + arg++; + continue; + } + switch (cmd) { + case 'a': + case 'A': { + char pad = (char) (cmd == 'a' ? '\0' : ' '); + + str = Tcl_GetStringFromObj(objv[arg++], &length); + + if (count == BINARY_ALL) { + count = length; + } else if (count == BINARY_NOCOUNT) { + count = 1; + } + if (length >= count) { + memcpy((VOID *) cursor, (VOID *) str, + (size_t) count); + } else { + memcpy((VOID *) cursor, (VOID *) str, + (size_t) length); + memset(cursor+length, pad, + (size_t) (count - length)); + } + cursor += count; + break; + } + case 'b': + case 'B': { + char *last; + + str = Tcl_GetStringFromObj(objv[arg++], &length); + if (count == BINARY_ALL) { + count = length; + } else if (count == BINARY_NOCOUNT) { + count = 1; + } + last = cursor + ((count + 7) / 8); + if (count > length) { + count = length; + } + value = 0; + errorString = "binary"; + if (cmd == 'B') { + for (offset = 0; offset < count; offset++) { + value <<= 1; + if (str[offset] == '1') { + value |= 1; + } else if (str[offset] != '0') { + errorValue = str; + goto badValue; + } + if (((offset + 1) % 8) == 0) { + *cursor++ = (char)(value & 0xff); + value = 0; + } + } + } else { + for (offset = 0; offset < count; offset++) { + value >>= 1; + if (str[offset] == '1') { + value |= 128; + } else if (str[offset] != '0') { + errorValue = str; + goto badValue; + } + if (!((offset + 1) % 8)) { + *cursor++ = (char)(value & 0xff); + value = 0; + } + } + } + if ((offset % 8) != 0) { + if (cmd == 'B') { + value <<= 8 - (offset % 8); + } else { + value >>= 8 - (offset % 8); + } + *cursor++ = (char)(value & 0xff); + } + while (cursor < last) { + *cursor++ = '\0'; + } + break; + } + case 'h': + case 'H': { + char *last; + int c; + + str = Tcl_GetStringFromObj(objv[arg++], &length); + if (count == BINARY_ALL) { + count = length; + } else if (count == BINARY_NOCOUNT) { + count = 1; + } + last = cursor + ((count + 1) / 2); + if (count > length) { + count = length; + } + value = 0; + errorString = "hexadecimal"; + if (cmd == 'H') { + for (offset = 0; offset < count; offset++) { + value <<= 4; + c = tolower(((unsigned char *) str)[offset]); + if ((c >= 'a') && (c <= 'f')) { + value |= ((c - 'a' + 10) & 0xf); + } else if ((c >= '0') && (c <= '9')) { + value |= (c - '0') & 0xf; + } else { + errorValue = str; + goto badValue; + } + if (offset % 2) { + *cursor++ = (char) value; + value = 0; + } + } + } else { + for (offset = 0; offset < count; offset++) { + value >>= 4; + c = tolower(((unsigned char *) str)[offset]); + if ((c >= 'a') && (c <= 'f')) { + value |= ((c - 'a' + 10) << 4) & 0xf0; + } else if ((c >= '0') && (c <= '9')) { + value |= ((c - '0') << 4) & 0xf0; + } else { + errorValue = str; + goto badValue; + } + if (offset % 2) { + *cursor++ = (char)(value & 0xff); + value = 0; + } + } + } + if (offset % 2) { + if (cmd == 'H') { + value <<= 4; + } else { + value >>= 4; + } + *cursor++ = (char) value; + } + + while (cursor < last) { + *cursor++ = '\0'; + } + break; + } + case 'c': + case 's': + case 'S': + case 'i': + case 'I': + case 'd': + case 'f': { + int listc, i; + Tcl_Obj **listv; + + if (count == BINARY_NOCOUNT) { + /* + * Note that we are casting away the const-ness of + * objv, but this is safe since we aren't going to + * modify the array. + */ + + listv = (Tcl_Obj**)(objv + arg); + listc = 1; + count = 1; + } else { + Tcl_ListObjGetElements(interp, objv[arg], + &listc, &listv); + if (count == BINARY_ALL) { + count = listc; + } + } + arg++; + for (i = 0; i < count; i++) { + if (FormatNumber(interp, cmd, listv[i], &cursor) + != TCL_OK) { + return TCL_ERROR; + } + } + break; + } + case 'x': + if (count == BINARY_NOCOUNT) { + count = 1; + } + memset(cursor, 0, (size_t) count); + cursor += count; + break; + case 'X': + if (cursor > maxPos) { + maxPos = cursor; + } + if (count == BINARY_NOCOUNT) { + count = 1; + } + if ((count == BINARY_ALL) + || (count > (cursor - buffer))) { + cursor = buffer; + } else { + cursor -= count; + } + break; + case '@': + if (cursor > maxPos) { + maxPos = cursor; + } + if (count == BINARY_ALL) { + cursor = maxPos; + } else { + cursor = buffer + count; + } + break; + } + } + break; + + case BinaryScan: { + int i; + Tcl_Obj *valuePtr, *elementPtr; + + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, + "value formatString ?varName varName ...?"); + return TCL_ERROR; + } + buffer = Tcl_GetStringFromObj(objv[2], &length); + format = Tcl_GetStringFromObj(objv[3], NULL); + cursor = buffer; + arg = 4; + offset = 0; + while (*format != 0) { + if (!GetFormatSpec(&format, &cmd, &count)) { + goto done; + } + switch (cmd) { + case 'a': + case 'A': + if (arg >= objc) { + goto badIndex; + } + if (count == BINARY_ALL) { + count = length - offset; + } else { + if (count == BINARY_NOCOUNT) { + count = 1; + } + if (count > (length - offset)) { + goto done; + } + } + + str = buffer + offset; + size = count; + + /* + * Trim trailing nulls and spaces, if necessary. + */ + + if (cmd == 'A') { + while (size > 0) { + if (str[size-1] != '\0' && str[size-1] != ' ') { + break; + } + size--; + } + } + valuePtr = Tcl_NewStringObj(str, size); + resultPtr = Tcl_ObjSetVar2(interp, objv[arg++], NULL, + valuePtr, + TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1); + if (resultPtr == NULL) { + Tcl_DecrRefCount(valuePtr); /* unneeded */ + return TCL_ERROR; + } + offset += count; + break; + case 'b': + case 'B': { + char *dest; + + if (arg >= objc) { + goto badIndex; + } + if (count == BINARY_ALL) { + count = (length - offset)*8; + } else { + if (count == BINARY_NOCOUNT) { + count = 1; + } + if (count > (length - offset)*8) { + goto done; + } + } + str = buffer + offset; + valuePtr = Tcl_NewObj(); + Tcl_SetObjLength(valuePtr, count); + dest = Tcl_GetStringFromObj(valuePtr, NULL); + + if (cmd == 'b') { + for (i = 0; i < count; i++) { + if (i % 8) { + value >>= 1; + } else { + value = *str++; + } + *dest++ = (char) ((value & 1) ? '1' : '0'); + } + } else { + for (i = 0; i < count; i++) { + if (i % 8) { + value <<= 1; + } else { + value = *str++; + } + *dest++ = (char) ((value & 0x80) ? '1' : '0'); + } + } + + resultPtr = Tcl_ObjSetVar2(interp, objv[arg++], NULL, + valuePtr, + TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1); + if (resultPtr == NULL) { + Tcl_DecrRefCount(valuePtr); /* unneeded */ + return TCL_ERROR; + } + offset += (count + 7 ) / 8; + break; + } + case 'h': + case 'H': { + char *dest; + int i; + static char hexdigit[] = "0123456789abcdef"; + + if (arg >= objc) { + goto badIndex; + } + if (count == BINARY_ALL) { + count = (length - offset)*2; + } else { + if (count == BINARY_NOCOUNT) { + count = 1; + } + if (count > (length - offset)*2) { + goto done; + } + } + str = buffer + offset; + valuePtr = Tcl_NewObj(); + Tcl_SetObjLength(valuePtr, count); + dest = Tcl_GetStringFromObj(valuePtr, NULL); + + if (cmd == 'h') { + for (i = 0; i < count; i++) { + if (i % 2) { + value >>= 4; + } else { + value = *str++; + } + *dest++ = hexdigit[value & 0xf]; + } + } else { + for (i = 0; i < count; i++) { + if (i % 2) { + value <<= 4; + } else { + value = *str++; + } + *dest++ = hexdigit[(value >> 4) & 0xf]; + } + } + + resultPtr = Tcl_ObjSetVar2(interp, objv[arg++], NULL, + valuePtr, + TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1); + if (resultPtr == NULL) { + Tcl_DecrRefCount(valuePtr); /* unneeded */ + return TCL_ERROR; + } + offset += (count + 1) / 2; + break; + } + case 'c': + size = 1; + goto scanNumber; + case 's': + case 'S': + size = 2; + goto scanNumber; + case 'i': + case 'I': + size = 4; + goto scanNumber; + case 'f': + size = sizeof(float); + goto scanNumber; + case 'd': + size = sizeof(double); + /* fall through */ + scanNumber: + if (arg >= objc) { + goto badIndex; + } + if (count == BINARY_NOCOUNT) { + if ((length - offset) < size) { + goto done; + } + valuePtr = ScanNumber(buffer+offset, cmd); + offset += size; + } else { + if (count == BINARY_ALL) { + count = (length - offset) / size; + } + if ((length - offset) < (count * size)) { + goto done; + } + valuePtr = Tcl_NewObj(); + str = buffer+offset; + for (i = 0; i < count; i++) { + elementPtr = ScanNumber(str, cmd); + str += size; + Tcl_ListObjAppendElement(NULL, valuePtr, + elementPtr); + } + offset += count*size; + } + + resultPtr = Tcl_ObjSetVar2(interp, objv[arg++], NULL, + valuePtr, + TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1); + if (resultPtr == NULL) { + Tcl_DecrRefCount(valuePtr); /* unneeded */ + return TCL_ERROR; + } + break; + case 'x': + if (count == BINARY_NOCOUNT) { + count = 1; + } + if ((count == BINARY_ALL) + || (count > (length - offset))) { + offset = length; + } else { + offset += count; + } + break; + case 'X': + if (count == BINARY_NOCOUNT) { + count = 1; + } + if ((count == BINARY_ALL) || (count > offset)) { + offset = 0; + } else { + offset -= count; + } + break; + case '@': + if (count == BINARY_NOCOUNT) { + goto badCount; + } + if ((count == BINARY_ALL) || (count > length)) { + offset = length; + } else { + offset = count; + } + break; + default: { + char buf[2]; + + Tcl_ResetResult(interp); + buf[0] = cmd; + buf[1] = '\0'; + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "bad field specifier \"", buf, "\"", NULL); + return TCL_ERROR; + } + } + } + + /* + * Set the result to the last position of the cursor. + */ + + done: + Tcl_ResetResult(interp); + Tcl_SetLongObj(Tcl_GetObjResult(interp), arg - 4); + break; + } + } + return TCL_OK; + + badValue: + Tcl_ResetResult(interp); + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "expected ", errorString, + " string but got \"", errorValue, "\" instead", NULL); + return TCL_ERROR; + + badCount: + errorString = "missing count for \"@\" field specifier"; + goto error; + + badIndex: + errorString = "not enough arguments for all format specifiers"; + goto error; + + error: + Tcl_ResetResult(interp); + Tcl_AppendToObj(Tcl_GetObjResult(interp), errorString, -1); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * GetFormatSpec -- + * + * This function parses the format strings used in the binary + * format and scan commands. + * + * Results: + * Moves the formatPtr to the start of the next command. Returns + * the current command character and count in cmdPtr and countPtr. + * The count is set to BINARY_ALL if the count character was '*' + * or BINARY_NOCOUNT if no count was specified. Returns 1 on + * success, or 0 if the string did not have a format specifier. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +GetFormatSpec(formatPtr, cmdPtr, countPtr) + char **formatPtr; /* Pointer to format string. */ + char *cmdPtr; /* Pointer to location of command char. */ + int *countPtr; /* Pointer to repeat count value. */ +{ + /* + * Skip any leading blanks. + */ + + while (**formatPtr == ' ') { + (*formatPtr)++; + } + + /* + * The string was empty, except for whitespace, so fail. + */ + + if (!(**formatPtr)) { + return 0; + } + + /* + * Extract the command character and any trailing digits or '*'. + */ + + *cmdPtr = **formatPtr; + (*formatPtr)++; + if (**formatPtr == '*') { + (*formatPtr)++; + (*countPtr) = BINARY_ALL; + } else if (isdigit(**formatPtr)) { + (*countPtr) = strtoul(*formatPtr, formatPtr, 10); + } else { + (*countPtr) = BINARY_NOCOUNT; + } + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * FormatNumber -- + * + * This routine is called by Tcl_BinaryObjCmd to format a number + * into a location pointed at by cursor. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Moves the cursor to the next location to be written into. + * + *---------------------------------------------------------------------- + */ + +static int +FormatNumber(interp, type, src, cursorPtr) + Tcl_Interp *interp; /* Current interpreter, used to report + * errors. */ + int type; /* Type of number to format. */ + Tcl_Obj *src; /* Number to format. */ + char **cursorPtr; /* Pointer to index into destination buffer. */ +{ + int value; + double dvalue; + char cmd = (char)type; + + if (cmd == 'd' || cmd == 'f') { + /* + * For floating point types, we need to copy the data using + * memcpy to avoid alignment issues. + */ + + if (Tcl_GetDoubleFromObj(interp, src, &dvalue) != TCL_OK) { + return TCL_ERROR; + } + if (cmd == 'd') { + memcpy((*cursorPtr), &dvalue, sizeof(double)); + (*cursorPtr) += sizeof(double); + } else { + float fvalue; + + /* + * Because some compilers will generate floating point exceptions + * on an overflow cast (e.g. Borland), we restrict the values + * to the valid range for float. + */ + + if (fabs(dvalue) > (double)FLT_MAX) { + fvalue = (dvalue >= 0.0) ? FLT_MAX : -FLT_MAX; + } else { + fvalue = (float) dvalue; + } + memcpy((*cursorPtr), &fvalue, sizeof(float)); + (*cursorPtr) += sizeof(float); + } + } else { + if (Tcl_GetIntFromObj(interp, src, &value) != TCL_OK) { + return TCL_ERROR; + } + if (cmd == 'c') { + *(*cursorPtr)++ = (char)(value & 0xff); + } else if (cmd == 's') { + *(*cursorPtr)++ = (char)(value & 0xff); + *(*cursorPtr)++ = (char)((value >> 8) & 0xff); + } else if (cmd == 'S') { + *(*cursorPtr)++ = (char)((value >> 8) & 0xff); + *(*cursorPtr)++ = (char)(value & 0xff); + } else if (cmd == 'i') { + *(*cursorPtr)++ = (char)(value & 0xff); + *(*cursorPtr)++ = (char)((value >> 8) & 0xff); + *(*cursorPtr)++ = (char)((value >> 16) & 0xff); + *(*cursorPtr)++ = (char)((value >> 24) & 0xff); + } else if (cmd == 'I') { + *(*cursorPtr)++ = (char)((value >> 24) & 0xff); + *(*cursorPtr)++ = (char)((value >> 16) & 0xff); + *(*cursorPtr)++ = (char)((value >> 8) & 0xff); + *(*cursorPtr)++ = (char)(value & 0xff); + } + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ScanNumber -- + * + * This routine is called by Tcl_BinaryObjCmd to scan a number + * out of a buffer. + * + * Results: + * Returns a newly created object containing the scanned number. + * This object has a ref count of zero. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_Obj * +ScanNumber(buffer, type) + char *buffer; /* Buffer to scan number from. */ + int type; /* Format character from "binary scan" */ +{ + int value; + + /* + * We cannot rely on the compiler to properly sign extend integer values + * when we cast from smaller values to larger values because we don't know + * the exact size of the integer types. So, we have to handle sign + * extension explicitly by checking the high bit and padding with 1's as + * needed. + */ + + switch ((char) type) { + case 'c': + value = buffer[0]; + + if (value & 0x80) { + value |= -0x100; + } + return Tcl_NewLongObj((long)value); + case 's': + value = (((unsigned char)buffer[0]) + + ((unsigned char)buffer[1] << 8)); + goto shortValue; + case 'S': + value = (((unsigned char)buffer[1]) + + ((unsigned char)buffer[0] << 8)); + shortValue: + if (value & 0x8000) { + value |= -0x10000; + } + return Tcl_NewLongObj((long)value); + case 'i': + value = (((unsigned char)buffer[0]) + + ((unsigned char)buffer[1] << 8) + + ((unsigned char)buffer[2] << 16) + + ((unsigned char)buffer[3] << 24)); + goto intValue; + case 'I': + value = (((unsigned char)buffer[3]) + + ((unsigned char)buffer[2] << 8) + + ((unsigned char)buffer[1] << 16) + + ((unsigned char)buffer[0] << 24)); + intValue: + /* + * Check to see if the value was sign extended properly on + * systems where an int is more than 32-bits. + */ + + if ((value & (((unsigned int)1)<<31)) && (value > 0)) { + value -= (((unsigned int)1)<<31); + value -= (((unsigned int)1)<<31); + } + + return Tcl_NewLongObj((long)value); + case 'f': { + float fvalue; + memcpy(&fvalue, buffer, sizeof(float)); + return Tcl_NewDoubleObj(fvalue); + } + case 'd': { + double dvalue; + memcpy(&dvalue, buffer, sizeof(double)); + return Tcl_NewDoubleObj(dvalue); + } + } + return NULL; +} |