summaryrefslogtreecommitdiff
path: root/portable
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit8fc5a7f51e62cb4ae44a27bdf4176d04adc80ede (patch)
treeabe4f8fc84569829299f1bd8d22a32b895117813 /portable
downloadsrec-8fc5a7f51e62cb4ae44a27bdf4176d04adc80ede.tar.gz
Initial Contributionandroid-1.0
Diffstat (limited to 'portable')
-rw-r--r--portable/Android.mk75
-rw-r--r--portable/include/ArrayList.h295
-rw-r--r--portable/include/ArrayListImpl.h120
-rw-r--r--portable/include/ESR_ReturnCode.h220
-rw-r--r--portable/include/LCHAR.h170
-rw-r--r--portable/include/PANSIFileImpl.h134
-rw-r--r--portable/include/PANSIFileSystem.h156
-rw-r--r--portable/include/PANSIFileSystemImpl.h113
-rw-r--r--portable/include/PFile.h597
-rw-r--r--portable/include/PFileImpl.h82
-rw-r--r--portable/include/PFileSystem.h225
-rw-r--r--portable/include/PFileSystemImpl.h115
-rw-r--r--portable/include/PStackSize.h42
-rw-r--r--portable/include/PStackTrace.h111
-rw-r--r--portable/include/PortExport.h123
-rw-r--r--portable/include/PortPrefix.h33
-rw-r--r--portable/include/pLastError.h37
-rw-r--r--portable/include/passert.h71
-rw-r--r--portable/include/pcputimer.h95
-rw-r--r--portable/include/pcrc.h76
-rw-r--r--portable/include/pendian.h110
-rw-r--r--portable/include/phashtable.h283
-rw-r--r--portable/include/plog.h338
-rw-r--r--portable/include/pmalloc.h113
-rw-r--r--portable/include/pmemory.h309
-rw-r--r--portable/include/pmutex.h96
-rw-r--r--portable/include/pstdio.h97
-rw-r--r--portable/include/pstream.h105
-rw-r--r--portable/include/ptimer.h86
-rw-r--r--portable/include/ptimestamp.h74
-rw-r--r--portable/include/ptrd.h494
-rw-r--r--portable/include/ptstutils.h65
-rw-r--r--portable/include/ptypes.h494
-rw-r--r--portable/src/ArrayList.c132
-rw-r--r--portable/src/ArrayListImpl.c241
-rw-r--r--portable/src/ESR_ReturnCode.c143
-rw-r--r--portable/src/LCHAR.c355
-rw-r--r--portable/src/PANSIFileImpl.c449
-rw-r--r--portable/src/PANSIFileSystem.c52
-rw-r--r--portable/src/PANSIFileSystemImpl.c365
-rw-r--r--portable/src/PFile.c521
-rw-r--r--portable/src/PFileImpl.c199
-rw-r--r--portable/src/PFileSystem.c552
-rw-r--r--portable/src/PFileSystemImpl.c107
-rw-r--r--portable/src/PFileWrap.c513
-rw-r--r--portable/src/PStackSize.c61
-rw-r--r--portable/src/UNIX/PANSIFileSystemUNIXImpl.c166
-rw-r--r--portable/src/UNIX/PFileSystemUNIXImpl.c142
-rw-r--r--portable/src/UNIX/PFileWrapUNIX_OS_Specific.c116
-rw-r--r--portable/src/pLastError.c65
-rw-r--r--portable/src/pcputimer.c238
-rw-r--r--portable/src/pcrc.c159
-rw-r--r--portable/src/pendian.c49
-rw-r--r--portable/src/phashtable.c560
-rw-r--r--portable/src/plog.c538
-rw-r--r--portable/src/pmalloc.c610
-rw-r--r--portable/src/pmemblock.c544
-rw-r--r--portable/src/pmemfixed.c705
-rw-r--r--portable/src/pmemory.c956
-rw-r--r--portable/src/pmemory_ext.c369
-rw-r--r--portable/src/pmemory_ext.h47
-rw-r--r--portable/src/pstream.c990
-rw-r--r--portable/src/ptimer.c264
-rw-r--r--portable/src/ptimestamp.c56
-rw-r--r--portable/src/ptypes.c38
65 files changed, 15856 insertions, 0 deletions
diff --git a/portable/Android.mk b/portable/Android.mk
new file mode 100644
index 0000000..a66f687
--- /dev/null
+++ b/portable/Android.mk
@@ -0,0 +1,75 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# common settings for all ASR builds, exports some variables for sub-makes
+include $(ASR_MAKE_DIR)/Makefile.defs
+
+common_SRC_FILES:= \
+ src/ArrayList.c \
+ src/ArrayListImpl.c \
+ src/ESR_ReturnCode.c \
+ src/LCHAR.c \
+ src/pcputimer.c \
+ src/pcrc.c \
+ src/pendian.c \
+ src/PFileWrap.c \
+ src/$(ASR_TARGET_OS)/PFileWrap$(ASR_TARGET_OS)_OS_Specific.c \
+ src/phashtable.c \
+ src/pLastError.c \
+ src/plog.c \
+ src/pmalloc.c \
+ src/pmemory.c \
+ src/pmemory_ext.c \
+ src/PStackSize.c \
+ src/ptimestamp.c \
+ src/ptypes.c \
+# src/ptimer.c \
+
+common_C_INCLUDES := \
+ $(ASR_ROOT_DIR)/portable/include \
+ $(ASR_ROOT_DIR)/shared/include \
+
+common_CFLAGS := \
+ -DPORTABLE_EXPORTS \
+
+common_CFLAGS += \
+ $(ASR_GLOBAL_DEFINES) \
+ $(ASR_GLOBAL_CPPFLAGS) \
+
+common_SHARED_LIBRARIES :=
+
+common_TARGET:= libESR_Portable
+
+
+# For the host
+# =====================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(common_SRC_FILES)
+LOCAL_C_INCLUDES := $(common_C_INCLUDES)
+LOCAL_CFLAGS += $(common_CFLAGS)
+
+#LOCAL_SHARED_LIBRARIES := $(common_SHARED_LIBRARIES)
+
+LOCAL_MODULE := $(common_TARGET)
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+
+# For the device
+# =====================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(common_SRC_FILES)
+LOCAL_C_INCLUDES := $(common_C_INCLUDES)
+LOCAL_CFLAGS += $(common_CFLAGS)
+
+LOCAL_SHARED_LIBRARIES := libcutils libmedia
+
+LOCAL_MODULE := $(common_TARGET)
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/portable/include/ArrayList.h b/portable/include/ArrayList.h
new file mode 100644
index 0000000..7d0ebfb
--- /dev/null
+++ b/portable/include/ArrayList.h
@@ -0,0 +1,295 @@
+/*---------------------------------------------------------------------------*
+ * ArrayList.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __ARRAYLIST_H
+#define __ARRAYLIST_H
+
+
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+#include "ptypes.h"
+#include <stdlib.h>
+
+/**
+ * @addtogroup ArrayListModule ArrayList API functions
+ * Collection of elements.
+ *
+ * @{
+ */
+
+/**
+ * Collection of elements.
+ */
+typedef struct ArrayList_t
+{
+ /**
+ * Adds element to list.
+ *
+ * @param self ArrayList handle
+ * @param element Element to be added
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_OUT_OF_MEMORY is system is out of memory
+ */
+ ESR_ReturnCode(*add)(struct ArrayList_t* self, void* element);
+
+ /**
+ * Inserts an element in the the list at the specified location. This
+ * causes all elements above or at the specified location to be shifted by
+ * one.
+ *
+ * @param self ArrayList handle
+ * @param index The index where to insert the element.
+ * @param element The element to insert.
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_SUCCESS if success or anaother value indicating
+ * the nature of the error. In particular, it returns ESR_ARGUMENT_OUT_OF_BOUNDS if index
+ * is less than 0 or greater than the array's size.
+ */
+ ESR_ReturnCode(*insertAt)(struct ArrayList_t* self, size_t index,
+ void *element);
+
+ /**
+ * Removes element from list.
+ *
+ * @param self ArrayList handle
+ * @param element Element to be removed
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_OUT_OF_MEMORY is system is out of memory
+ */
+ ESR_ReturnCode(*remove)(struct ArrayList_t* self, const void* element);
+
+ /**
+ * Removes element from list at specified index.
+ *
+ * @param self ArrayList handle
+ * @param index Index of element to be removed
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_OUT_OF_MEMORY is system is out of memory;
+ * ESR_ARGUMENT_OUT_OF_BOUNDS if index is out of bounds
+ */
+ ESR_ReturnCode(*removeAtIndex)(struct ArrayList_t* self, size_t index);
+
+ /**
+ * Removes all elements from list.
+ *
+ * @param self ArrayList handle
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*removeAll)(struct ArrayList_t* self);
+
+ /**
+ * Indicates if element is contained within the list.
+ *
+ * @param self ArrayList handle
+ * @param element Element to check for
+ * @param exists True if element was found
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*contains)(struct ArrayList_t* self, const void* element, ESR_BOOL* exists);
+
+ /**
+ * Returns array size.
+ *
+ * @param self ArrayList handle
+ * @param size Returned size
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*getSize)(struct ArrayList_t* self, size_t* size);
+
+ /**
+ * Returns the element at the specified index.
+ *
+ * @param self ArrayList handle
+ * @param index Element index
+ * @param element Element being returned
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_ARGUMENT_OUT_OF_BOUNDS if index is out of bounds
+ */
+ ESR_ReturnCode(*get)(struct ArrayList_t* self, size_t index, void** element);
+
+ /**
+ * Sets the element at the specified index.
+ *
+ * NOTE: Does *not* deallocate the element being overwritten.
+ * @param self ArrayList handle
+ * @param index Element index
+ * @param element Element's new value
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_ARGUMENT_OUT_OF_BOUNDS if index is out of bounds
+ */
+ ESR_ReturnCode(*set)(struct ArrayList_t* self, size_t index, void* element);
+
+ /**
+ * Converts the ArrayList to a static array.
+ * The use of the ArrayList handle is undefined past this point.
+ *
+ * @param self ArrayList handle
+ * @param newArray Pointer to resulting array
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*toStaticArray)(struct ArrayList_t* self, void** newArray);
+
+ /**
+ * Returns a clone of the ArrayList.
+ *
+ * @param self ArrayList handle
+ * @param clone [out] Clone of the ArrayList (created externally, populated internally)
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_ARGUMENT_OUT_OF_BOUNDS if index (used internally) is out of bounds
+ * ESR_OUT_OF_MEMORY is system is out of memory
+ */
+ ESR_ReturnCode(*clone)(struct ArrayList_t* self, struct ArrayList_t* clone);
+
+ /**
+ * Destroys the ArrayList.
+ *
+ * @param self ArrayList handle
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*destroy)(struct ArrayList_t* self);
+}
+ArrayList;
+
+/**
+ * Creates a new ArrayList.
+ *
+ * @param self ArrayList handle
+ * @return ESR_INVALID_ARGUMENT if self or the value it points to are null; ESR_OUT_OF_MEMORY is system is out of memory
+ */
+PORTABLE_API ESR_ReturnCode ArrayListCreate(ArrayList** self);
+
+/**
+ * Creates a new ArrayList with minimum capacity.
+ *
+ * @param self ArrayList handle
+ * @param minCapacity Minimum capacity of the array.
+ * @return ESR_INVALID_ARGUMENT if self or the value it points to are null; ESR_OUT_OF_MEMORY is system is out of memory
+ */
+PORTABLE_API ESR_ReturnCode ArrayListCreateWithCapacity(ArrayList** self, size_t minCapacity);
+
+/**
+ * Adds element to list.
+ *
+ * @param self ArrayList handle
+ * @param element Element to be added
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_OUT_OF_MEMORY is system is out of memory
+ */
+PORTABLE_API ESR_ReturnCode ArrayListAdd(ArrayList* self, void* element);
+
+
+/**
+ * Inserts an element in the the list at the specified location. This
+ * causes all elements above or at the specified location to be shifted by
+ * one.
+ *
+ * @param self ArrayList handle
+ * @param index The index where to insert the element.
+ * @param element The element to insert.
+ *
+ * @return ESR_SUCCESS if success or anaother value indicating the nature of
+ * the error. In particular, it returns ESR_ARGUMENT_OUT_OF_BOUNDS if index
+ * is less than 0 or greater than the array's size.
+ */
+PORTABLE_API ESR_ReturnCode ArrayListInsertAt(ArrayList* self,
+ size_t index,
+ void *element);
+
+/**
+ * Removes element from list.
+ *
+ * @param self ArrayList handle
+ * @param element Element to be removed
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_OUT_OF_MEMORY is system is out of memory
+ */
+PORTABLE_API ESR_ReturnCode ArrayListRemove(ArrayList* self, void* element);
+/**
+ * Removes element from list at specified index.
+ *
+ * @param self ArrayList handle
+ * @param index Index of element to be removed
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_OUT_OF_MEMORY is system is out of memory;
+ * ESR_ARGUMENT_OUT_OF_BOUNDS if index is out of bounds
+ */
+PORTABLE_API ESR_ReturnCode ArrayListRemoveAtIndex(ArrayList* self, size_t index);
+
+/**
+ * Removes all elements from list.
+ *
+ * @param self ArrayList handle
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode ArrayListRemoveAll(ArrayList* self);
+
+/**
+ * Indicates if element is contained within the list.
+ *
+ * @param self ArrayList handle
+ * @param element Element to check for
+ * @param exists True if element was found
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode ArrayListContains(ArrayList* self, void* element, ESR_BOOL* exists);
+
+/**
+ * Returns array size.
+ *
+ * @param self ArrayList handle
+ * @param size Returned size
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode ArrayListGetSize(ArrayList* self, size_t* size);
+
+/**
+ * Returns the element at the specified index.
+ *
+ * @param self ArrayList handle
+ * @param index Element index
+ * @param element Element being returned
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_ARGUMENT_OUT_OF_BOUNDS if index is out of bounds
+ */
+PORTABLE_API ESR_ReturnCode ArrayListGet(ArrayList* self, size_t index, void** element);
+
+/**
+ * Sets the element at the specified index.
+ *
+ * NOTE: Does *not* deallocate the element being overwritten.
+ * @param self ArrayList handle
+ * @param index Element index
+ * @param element Element's new value
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_ARGUMENT_OUT_OF_BOUNDS if index is out of bounds
+ */
+PORTABLE_API ESR_ReturnCode ArrayListSet(ArrayList* self, size_t index, void* element);
+
+/**
+ * Returns a clone of the ArrayList.
+ *
+ * @param self ArrayList handle
+ * @param clone [out] Clone of the ArrayList (created externally, populated internally)
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_ARGUMENT_OUT_OF_BOUNDS if index (used internally) is out of bounds
+ * ESR_OUT_OF_MEMORY is system is out of memory
+ */
+PORTABLE_API ESR_ReturnCode ArrayListClone(ArrayList* self, ArrayList* clone);
+
+/**
+ * Destroys an ArrayList.
+ *
+ * @param self ArrayList handle
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode ArrayListDestroy(ArrayList* self);
+
+/**
+ * @}
+ */
+
+#endif /* __ARRAYLIST_H */
diff --git a/portable/include/ArrayListImpl.h b/portable/include/ArrayListImpl.h
new file mode 100644
index 0000000..09c679c
--- /dev/null
+++ b/portable/include/ArrayListImpl.h
@@ -0,0 +1,120 @@
+/*---------------------------------------------------------------------------*
+ * ArrayListImpl.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __ARRAYLISTIMPL_H
+#define __ARRAYLISTIMPL_H
+
+
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+
+/**
+ * ArrayList implementation.
+ */
+typedef struct ArrayListImpl_t
+{
+ /**
+ * Interface functions that must be implemented.
+ */
+ ArrayList Interface;
+
+ /**
+ * ArrayList contents.
+ *
+ * Represents an array of void* elements. An element having a value of NULL denotes an
+ * empty slot.
+ */
+ void** contents;
+
+ /**
+ * number element in the array.
+ */
+ size_t size;
+
+ /**
+ * Actual capacity of the array.
+ */
+ size_t capacity;
+
+ /**
+ * Min capacity of the array.
+ **/
+ size_t minCapacity;
+
+}
+ArrayListImpl;
+
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_Add(ArrayList* self, void* element);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_InsertAt(ArrayList* self, size_t index, void* element);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_Remove(ArrayList* self, const void* element);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_RemoveAtIndex(ArrayList* self, size_t index);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_RemoveAll(ArrayList* self);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_Contains(ArrayList* self, const void* element, ESR_BOOL* exists);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_Get(ArrayList* self, size_t index, void** element);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_Set(ArrayList* self, size_t index, void* element);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_GetSize(ArrayList* self, size_t* size);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_Clone(ArrayList* self, ArrayList* clone);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode ArrayList_Destroy(ArrayList* self);
+
+#endif /* __ARRAYLIST_H */
diff --git a/portable/include/ESR_ReturnCode.h b/portable/include/ESR_ReturnCode.h
new file mode 100644
index 0000000..4fdd906
--- /dev/null
+++ b/portable/include/ESR_ReturnCode.h
@@ -0,0 +1,220 @@
+/*---------------------------------------------------------------------------*
+ * ESR_ReturnCode.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef ESR_RETURNCODE_H
+#define ESR_RETURNCODE_H
+
+
+
+#include "PortPrefix.h"
+
+/**
+ * @addtogroup ESR_PortableModule ESR_Portable API functions
+ *
+ * @{
+ */
+
+/**
+ * Return-code values.
+ */
+typedef enum ESR_ReturnCode_t
+{
+ /*
+ * Note: do not forget to modify ESR_rc2str when modifying this enum.
+ */
+
+ /**
+ * Operation completed successfully.
+ */
+ ESR_SUCCESS,
+
+ /**
+ * Intermediate stage of operation completed successfully, we wish to indicate
+ * that remainig stages of operation may proceed.
+ */
+ ESR_CONTINUE_PROCESSING,
+
+ /**
+ * Indicates a fatal error.
+ */
+ ESR_FATAL_ERROR,
+
+ /**
+ * Buffer overflow occured.
+ */
+ ESR_BUFFER_OVERFLOW,
+
+ /**
+ * Error typing to open an entity or the operation failed because the entity was not opened.
+ */
+ ESR_OPEN_ERROR,
+
+ /**
+ * Error trying to open an entity that is already open.
+ */
+ ESR_ALREADY_OPEN,
+
+ /**
+ * Error typing to close a entity or the operation failed because the entity was not closed.
+ */
+ ESR_CLOSE_ERROR,
+
+ /**
+ * Error trying to close a entity that was already closed.
+ */
+ ESR_ALREADY_CLOSED,
+
+ /**
+ * Error trying to read a file.
+ */
+ ESR_READ_ERROR,
+
+ /**
+ * Error trying to write to a entity.
+ */
+ ESR_WRITE_ERROR,
+
+ /**
+ * Error trying to flush a entity.
+ */
+ ESR_FLUSH_ERROR,
+
+ /**
+ * Error trying to seek a entity.
+ */
+ ESR_SEEK_ERROR,
+
+ /**
+ * Error trying to allocate memory.
+ */
+ ESR_OUT_OF_MEMORY,
+
+ /**
+ * Specified argument is out of bounds.
+ */
+ ESR_ARGUMENT_OUT_OF_BOUNDS,
+
+ /**
+ * Failed to locate the specified entity.
+ */
+ ESR_NO_MATCH_ERROR,
+
+ /**
+ * Passed in argument contains an invalid value. Such as when a NULL pointer
+ * is passed in when when an actual value is expected.
+ */
+ ESR_INVALID_ARGUMENT,
+
+ /**
+ * Indicates that request functionality is not supported.
+ */
+ ESR_NOT_SUPPORTED,
+
+ /**
+ * Indicates that the object is not in a state such that the operation can
+ * be succesfully performed.
+ */
+ ESR_INVALID_STATE,
+
+ /**
+ * Indicates that a thread could not be created.
+ */
+ ESR_THREAD_CREATION_ERROR,
+
+ /**
+ * Indicates that a resource with the same identifier already exists.
+ */
+ ESR_IDENTIFIER_COLLISION,
+
+ /**
+ * Indicates that the operation timed out.
+ */
+ ESR_TIMED_OUT,
+
+ /**
+ * Indicates that the object being retrieved isn't of the expected type.
+ * For example, when retrieving an integer from a HashMap we find out the
+ * value is actually of type float.
+ */
+ ESR_INVALID_RESULT_TYPE,
+
+ /**
+ * Indicates that the invoked function has not been implemented.
+ */
+ ESR_NOT_IMPLEMENTED,
+
+ /**
+ * A connection was forcibly closed by a peer. This normally results from
+ * a loss of the connection on the remote socket due to a timeout or a reboot.
+ */
+ ESR_CONNECTION_RESET_BY_PEER,
+
+ /**
+ * Indicates that a process could not be created.
+ */
+ ESR_PROCESS_CREATE_ERROR,
+
+ /**
+ * Indicates that no matching TTS engine is available.
+ */
+ ESR_TTS_NO_ENGINE,
+
+ /**
+ * Indicates that an attempt to create a mutex failed because the OS is running out of resources.
+ */
+ ESR_MUTEX_CREATION_ERROR,
+
+ /**
+ * Indicates a deadlock situation has occured.
+ */
+ ESR_DEADLOCK
+} ESR_ReturnCode;
+
+
+/**
+ * Checks the function return-code and if it is not ESR_SUCCESS, returns it.
+ */
+#define CHK(rc, x) do { if ((rc = (x)) != ESR_SUCCESS) goto CLEANUP; } while (0)
+
+#include "ptypes.h"
+
+/**
+ * Given a return-code, returns its string representation.
+ *
+ * @param rc Return-code
+ * @return String representation of return-code.
+ */
+PORTABLE_API const LCHAR* ESR_rc2str(const ESR_ReturnCode rc);
+
+#ifdef _WIN32
+/**
+ * Called before entering any function.
+ */
+PORTABLE_API void _cdecl _penter(void);
+/**
+ * Called after exiting any function.
+ */
+PORTABLE_API void _cdecl _pexit(void);
+#endif
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/portable/include/LCHAR.h b/portable/include/LCHAR.h
new file mode 100644
index 0000000..2bea16a
--- /dev/null
+++ b/portable/include/LCHAR.h
@@ -0,0 +1,170 @@
+/*---------------------------------------------------------------------------*
+ * LCHAR.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __LCHAR_H
+#define __LCHAR_H
+
+
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+#include "ptypes.h"
+
+/**
+ * @addtogroup LCHARModule LCHAR API functions
+ * LCHAR manipulation functions.
+ *
+ * @{
+ */
+
+/**
+ * Trims string, removing any leading, trailing whitespace.
+ *
+ * @param text Text to trim
+ * @return ESR_SUCCESS
+ */
+PORTABLE_API ESR_ReturnCode lstrtrim(LCHAR* text);
+
+/**
+ * Inserts text into a string.
+ *
+ * @param source String to insert
+ * @param target String to insert into
+ * @param offset Offset in target string
+ * @param len [in/out] Length of target argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_BUFFER_OVERFLOW is target is too small to insert into
+ */
+PORTABLE_API ESR_ReturnCode lstrinsert(const LCHAR* source, LCHAR* target, size_t offset, size_t* len);
+
+/**
+ * Changes all instances of one character to another in a string.
+ *
+ * @param text String to process
+ * @param source Source character
+ * @param target Target character
+ * @return ESR_SUCCESS
+ */
+PORTABLE_API ESR_ReturnCode lstrreplace(LCHAR* text, const LCHAR source, const LCHAR target);
+
+/**
+ * Converts string to integer.
+ *
+ * @param text String to parse
+ * @param result [out] Resulting value
+ * @param base Number base to use
+ * @return ESR_INVALID_ARGUMENT is text is null or does not represent a number
+ */
+PORTABLE_API ESR_ReturnCode lstrtoi(const LCHAR* text, int* result, int base);
+
+/**
+ * Converts string to unsigned integer.
+ *
+ * @param text String to parse
+ * @param result [out] Resulting value
+ * @param base Number base to use
+ * @return ESR_INVALID_ARGUMENT is text is null or does not represent a number
+ */
+PORTABLE_API ESR_ReturnCode lstrtoui(const LCHAR* text, unsigned int* result, int base);
+
+/**
+ * Converts string to float.
+ *
+ * @param text String to parse
+ * @param result [out] Resulting value
+ * @return ESR_INVALID_ARGUMENT is text is null or does not represent a number
+ */
+PORTABLE_API ESR_ReturnCode lstrtof(const LCHAR* text, float* result);
+
+/**
+ * Converts string to boolean.
+ *
+ * @param text String to parse
+ * @param result [out] Resulting value
+ * @return ESR_INVALID_ARGUMENT is text is null or does not represent a boolean value
+ */
+PORTABLE_API ESR_ReturnCode lstrtob(const LCHAR* text, ESR_BOOL* result);
+
+/**
+ * Returns the first token in the string in the form of an integer.
+ *
+ * @param text Text containing integers
+ * @param value [out] Integer that was read
+ * @param finalPosition [out] The first character after the token. A NULL value means this
+ * argument is ignored.
+ * @return ESR_INVALID_ARGUMENT is text is null or does not represent an integer value
+ */
+PORTABLE_API ESR_ReturnCode LCHARGetInt( LCHAR* text, int* value, LCHAR** finalPosition);
+
+/**
+ * Convert string to upper case
+ *
+ * @param string [in/out] string to be converted
+ * @return ESR_INVALID_ARGUMENT is string is null
+ */
+PORTABLE_API ESR_ReturnCode lstrupr(LCHAR* string);
+
+/**
+ * Convert string to lower case
+ *
+ * @param string [in/out] string to be converted
+ * @return ESR_INVALID_ARGUMENT is string is null
+ */
+PORTABLE_API ESR_ReturnCode lstrlwr(LCHAR* string);
+
+/**
+ * Binary safe case-insensitive string comparison
+ *
+ * @param string1 Text containing integers
+ * @param string2 Integer that was read
+ * @param result [out] returns
+ * < 0 if str1 is less than str2;
+ * > 0 if str1 is greater than str2, and
+ * 0 if they are equal.
+ * @return ESR_INVALID_ARGUMENT is string1 or string2 is null
+ */
+PORTABLE_API ESR_ReturnCode lstrcasecmp(const LCHAR *string1, const LCHAR *string2, int *result);
+
+/**
+ * Converts int to string
+ *
+ * @param value unsigned long to convert
+ * @param string [out] String to store
+ * @param len [in/out] in: length of the buffer; out: length of the converted string
+ * @param radix Base of value; must be in the range 2 - 36
+ * @return ESR_INVALID_ARGUMENT is string is null; ESR_BUFFER_OVERFLOW is string is not big enough to contain result
+ */
+PORTABLE_API ESR_ReturnCode litostr(int value, LCHAR *string, size_t *len, int radix);
+
+/**
+ * Converts unsigned long to string
+ *
+ * @param value unsigned long to convert
+ * @param string [out] String to store
+ * @param len [in/out] in: length of the buffer; out: length of the converted string
+ * @param radix Base of value; must be in the range 2 - 36
+ * @return ESR_INVALID_ARGUMENT is string is null; ESR_BUFFER_OVERFLOW is string is not big enough to contain result
+ */
+PORTABLE_API ESR_ReturnCode lultostr(unsigned long value, LCHAR *string, size_t *len, int radix);
+
+/**
+ * @}
+ */
+
+#endif /* __LCHAR_H */
diff --git a/portable/include/PANSIFileImpl.h b/portable/include/PANSIFileImpl.h
new file mode 100644
index 0000000..372eb93
--- /dev/null
+++ b/portable/include/PANSIFileImpl.h
@@ -0,0 +1,134 @@
+/*---------------------------------------------------------------------------*
+ * PANSIFileImpl.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PANSIFILEIMPL_H
+#define __PANSIFILEIMPL_H
+
+
+
+#include "PFile.h"
+#include "PFileImpl.h"
+#ifdef USE_THREAD
+#include "ptrd.h"
+#endif
+
+/**
+ * Portable file, ANSI implementation.
+ */
+typedef struct PANSIFileImpl_t
+{
+ /**
+ * Superinterface.
+ */
+ PFileImpl Interface;
+
+ /**
+ * Underlying file.
+ */
+ FILE* value;
+}
+PANSIFileImpl;
+
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileCreateImpl(const LCHAR* filename, ESR_BOOL isLittleEndian, PFile** self);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileDestroyImpl(PFile* self);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileOpenImpl(PFile* self, const LCHAR* mode);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileCloseImpl(PFile* self);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileReadImpl(PFile* self, void* buffer, size_t size, size_t* count);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileWriteImpl(PFile* self, void* buffer, size_t size, size_t* count);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileFlushImpl(PFile* self);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSeekImpl(PFile* self, long offset, int origin);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileGetPositionImpl(PFile* self, size_t* position);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileIsOpenImpl(PFile* self, ESR_BOOL* isOpen);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileIsEOFImpl(PFile* self, ESR_BOOL* isEof);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileIsErrorSetImpl(PFile* self, ESR_BOOL* isError);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileClearErrorImpl(PFile* self);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileVfprintfImpl(PFile* self, int* result, const LCHAR* format, va_list args);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileFgetcImpl(PFile* self, LINT* result);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileFgetsImpl(PFile* self, LCHAR* string, int n, LCHAR** result);
+
+/**
+ * ANSI implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileHideMemoryAllocation(PFile* self);
+
+#endif /* __PANSIFILEIMPL_H */
diff --git a/portable/include/PANSIFileSystem.h b/portable/include/PANSIFileSystem.h
new file mode 100644
index 0000000..2a409a3
--- /dev/null
+++ b/portable/include/PANSIFileSystem.h
@@ -0,0 +1,156 @@
+/*---------------------------------------------------------------------------*
+ * PANSIFileSystem.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PANSIFILESYSTEM_H
+#define __PANSIFILESYSTEM_H
+
+
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+#include "PFileSystem.h"
+#include "ptypes.h"
+
+/**
+ * @addtogroup PANSIFileSystemModule PANSIFileSystem API functions
+ * Portable file-system API.
+ *
+ * Must call pmemInit() before using this module.
+ * If threads are to be used, ptrdInit() must be called before using this module as well.
+ *
+ * NOTE: It is technically impossible to provide a cross-platform version of scanf() and its
+ * variants (since vscanf() does not exist). As a result, this module does not provide this
+ * functionality. End-users are encourages to do their own parsing.
+ *
+ * @{
+ */
+
+/**
+ * Portable ANSI file-system.
+ */
+typedef struct PANSIFileSystem_t
+{
+ /**
+ * Superinterface.
+ */
+ PFileSystem super;
+
+ /**
+ * Mounts an ANSI path.
+ *
+ * For example, if "c:/" is mounted as "/dev/c", then any file referenced under "/dev/c" will access
+ * "c:/" under the hood.
+ *
+ * @param self PFileSystem handle
+ * @param virtualPath PFileSystem path
+ * @param realPath ANSI path
+ * @return ESR_INVALID_ARGUMENT if self or virtualPath or realPath is null or realPath is not a valid path;
+ * ESR_OUT_OF_MEMORY if the system is out of memory; ESR_IDENTIFIER_COLLISION if virtualPath is already mounted.
+ */
+ ESR_ReturnCode(*addPath)(PFileSystem* self, const LCHAR* virtualPath, const LCHAR* realPath);
+
+ /**
+ * Deassociates the file-system from a base path.
+ *
+ * @param self PFileSystem handle
+ * @param virtualPath PFileSystem path
+ * @return ESR_INVALID_ARGUMENT if self or virtualPath is null or virtualPath is not mounted
+ */
+ ESR_ReturnCode(*removePath)(PFileSystem* self, const LCHAR* virtualPath);
+ /**
+ * Returns the current working directory from the operating-system's point of view.
+ * This differs from PFileSystemGetcwd() in that the latter returns the current working
+ * directory on the virtual file-system while this function returns the native working directory.
+ *
+ * @param self PFileSystem handle
+ * @param cwd [out] Current working directory
+ * @param len [in/out] Length of path argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_INVALID_ARGUMENT if self or cwd is null; ESR_BUFFER_OVERFLOW if cwd is not large enough to contain result;
+ * ESR_INVALID_STATE if operating-system returns unexpected value.
+ */
+ ESR_ReturnCode(*getcwd)(PFileSystem* self, LCHAR* cwd, size_t* len);
+}
+PANSIFileSystem;
+
+/**
+ * Initializes the ANSI file-system module.
+ *
+ * @return ESR_OUT_OF_MEMORY if system is out of memory; ESR_INVALID_STATE if mutex could not be created or if this
+ * function is called after the Ptrd module has been shut down.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemCreate(void);
+
+/**
+ * Shuts down the ANSI file-system module.
+ *
+ * @return ESR_SUCCESS
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemDestroy(void);
+
+/**
+ * Mounts an ANSI path.
+ *
+ * For example, if "c:/" is mounted as "/dev/c", then any file referenced under "/dev/c" will access
+ * "c:/" under the hood.
+ *
+ * @param virtualPath PFileSystem path
+ * @param realPath ANSI path
+ * @return ESR_INVALID_ARGUMENT if self or virtualPath or realPath is null or realPath is not a valid path;
+ * ESR_OUT_OF_MEMORY if the system is out of memory; ESR_IDENTIFIER_COLLISION if virtualPath is already mounted.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemAddPath(const LCHAR* virtualPath, const LCHAR* realPath);
+
+/**
+ * Deassociates the file-system from a base path.
+ *
+ * @param virtualPath PFileSystem path
+ * @return ESR_INVALID_ARGUMENT if self or virtualPath is null or virtualPath is not mounted
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemRemovePath(const LCHAR* virtualPath);
+
+/**
+ * Returns a virtual path associated with the current ANSI directory.
+ *
+ * For example, if "/dev/ansi" is mapped to "/" and the current ANSI directory is "/usr/bin" then
+ * this function will return "/dev/ansi/usr/bin".
+ *
+ * If multiple virtual paths correspond to the current ANSI directory, the first one will be returned.
+ *
+ * @param cwd [out] Current working directory
+ * @param len [in/out] Length of path argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_INVALID_ARGUMENT if self or cwd is null; ESR_BUFFER_OVERFLOW if cwd is not large enough to contain result;
+ * ESR_INVALID_STATE if operating-system returns unexpected value.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemGetcwd(LCHAR* cwd, size_t* len);
+
+/**
+ * Indicates if this file-system should act as the default file-system.
+ * If a path is specified which does not match any other file-system, it is resolved using this one.
+ *
+ * @param isDefault True if the file-system should be the default file-system
+ * @return ESR_OUT_OF_MEMORY if system is out of memory
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemSetDefault(ESR_BOOL isDefault);
+
+/**
+ * @}
+ */
+#endif /* __PANSIFILESYSTEM_H */
diff --git a/portable/include/PANSIFileSystemImpl.h b/portable/include/PANSIFileSystemImpl.h
new file mode 100644
index 0000000..2d14e75
--- /dev/null
+++ b/portable/include/PANSIFileSystemImpl.h
@@ -0,0 +1,113 @@
+/*---------------------------------------------------------------------------*
+ * PANSIFileSystemImpl.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PANSIFILESYSTEMIMPL_H
+#define __PANSIFILESYSTEMIMPL_H
+
+
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+#include "PANSIFileSystem.h"
+#include "phashtable.h"
+
+/**
+ * Portable file-system implementation.
+ */
+typedef struct PANSIFileSystemImpl_t
+{
+ /**
+ * Superinterface.
+ */
+ PANSIFileSystem super;
+
+ /**
+ * [virtualPath, realPath] mapping.
+ */
+ PHashTable* directoryMap;
+}
+PANSIFileSystemImpl;
+
+
+/**
+ * ANSI file system, singleton instance.
+ */
+PORTABLE_API PFileSystem* PANSIFileSystemSingleton;
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemDestroyImpl(PFileSystem* self);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemCreatePFileImpl(PFileSystem* self, const LCHAR* path, ESR_BOOL littleEndian, PFile** file);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemAddPathImpl(PFileSystem* self, const LCHAR* virtualPath, const LCHAR* realPath);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemRemovePathImpl(PFileSystem* self, const LCHAR* virtualPath);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemMkdirImpl(PFileSystem* self, const LCHAR* path);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemChdirImpl(PFileSystem* self, const LCHAR* path);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemGetcwdImpl(PFileSystem* self, LCHAR* cwd, size_t* len);
+
+/**
+ * Given a virtual-path, convert it to a real-path.
+ *
+ * @param self PFileSystem handle
+ * @param path Virtual-path
+ * @param len [out] Size of path argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemGetRealPathImpl(PFileSystem* self, LCHAR* path, size_t* len);
+
+/**
+ * Given a real-path, convert it to a virtual-path.
+ *
+ * @param self PFileSystem handle
+ * @param path Real path
+ * @param len [out] Size of path argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ */
+PORTABLE_API ESR_ReturnCode PANSIFileSystemGetVirtualPathImpl(PFileSystem* self, LCHAR* path, size_t* len);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemShutdownStreams(void);
+
+#endif /* __PANSIFILESYSTEMIMPL_H */
diff --git a/portable/include/PFile.h b/portable/include/PFile.h
new file mode 100644
index 0000000..1ae8605
--- /dev/null
+++ b/portable/include/PFile.h
@@ -0,0 +1,597 @@
+/*---------------------------------------------------------------------------*
+ * PFile.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PFILE_H
+#define __PFILE_H
+
+
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+#include "ptypes.h"
+#include "pstdio.h"
+
+
+/**
+ * @addtogroup PFileModule PFile API functions
+ * Portable file API.
+ *
+ * Must call pmemInit() before using this module.
+ * If threads are to be used, ptrdInit() must be called before using this module as well.
+ *
+ * NOTE: It is technically impossible to provide a cross-platform version of scanf() and its
+ * variants (since vscanf() does not exist). As a result, this module does not provide this
+ * functionality. End-users are encourages to do their own parsing.
+ *
+ * @{
+ */
+
+#define USE_LIGHT_WEIGHT_PANSI_FILE_WRAPPERS 1
+
+
+#ifdef USE_NARROW_CHAR
+
+/**
+ * Portable EOF constant
+ */
+#define PEOF EOF
+
+#else
+
+/**
+* Portable EOF constant
+*/
+#define PEOF WEOF
+
+#endif /* USE_NARROW_CHAR */
+
+/**
+ * Portable file.
+ */
+
+#ifdef USE_LIGHT_WEIGHT_PANSI_FILE_WRAPPERS
+
+typedef FILE PFile;
+
+#else
+typedef struct PFile_t
+{
+ /**
+ * Closes the PFile and destroys it.
+ *
+ * @param self PFile handle
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*destroy)(struct PFile_t* self);
+
+
+ ESR_ReturnCode(*open)(struct PFile_t* self, const LCHAR* mode);
+
+ /**
+ * Closes a PFile.
+ *
+ * @param self PFile handle
+ * @return ESR_CLOSE_ERROR if file cannot be closed
+ */
+ ESR_ReturnCode(*close)(struct PFile_t* self);
+
+ /**
+ * Reads from a PFile.
+ *
+ * @param self PFile handle
+ * @param buffer Storage location for data
+ * @param size Item size in bytes
+ * @param count [in/out] Maximum number of items to be read. On output, contains the
+ * number of full items actually read, which may be less than count if
+ * an error occurs or if the end of the file is encountered before reaching
+ * count.
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_READ_ERROR if a reading error occurs
+ */
+ ESR_ReturnCode(*read)(struct PFile_t* self, void* buffer, size_t size, size_t* count);
+
+ /**
+ * Writes data to a PFile.
+ *
+ * @param self PFile handle
+ * @param buffer Pointer to data to be written
+ * @param size Item size in bytes
+ * @param count [in/out] Maximum number of items to be read. On output, contains the
+ * number of full items actually written, which may be less than count if
+ * an error occurs.
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_WRITE_ERROR if a writing error occurs
+ */
+ ESR_ReturnCode(*write)(struct PFile_t* self, void* buffer, size_t size, size_t* count);
+
+ /**
+ * Flushes a PFile.
+ *
+ * @param self PFile handle
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_FLUSH_ERROR if a flushing error occurs
+ */
+ ESR_ReturnCode(*flush)(struct PFile_t* self);
+
+ /**
+ * Flushes a PFile.
+ *
+ * @param self PFile handle
+ * @param offset Number of bytes from <code>origin</code>
+ * @param origin Initial position
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_SEEK_ERROR if a seeking error occurs
+ */
+ ESR_ReturnCode(*seek)(struct PFile_t* self, long offset, int origin);
+
+ /**
+ * Gets the current position of a PFile.
+ *
+ * @param self PFile handle
+ * @param position [out] The position
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_INVALID_STATE if an internal error occurs
+ */
+ ESR_ReturnCode(*getPosition)(struct PFile_t* self, size_t* position);
+
+ /**
+ * Indicates if the PFile is open.
+ *
+ * @param self PFile handle
+ * @param isOpen [out] True if file is open
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*isOpen)(struct PFile_t* self, ESR_BOOL* isOpen);
+
+ /**
+ * Indicates if the PFile is at the end of file.
+ *
+ * @param self PFile handle
+ * @param isEof [out] True if end of file has been reached
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*isEOF)(struct PFile_t* self, ESR_BOOL* isEof);
+
+ /**
+ * Returns filename associated with PFile.
+ *
+ * @param self PFile handle
+ * @param filename [out] The filename
+ * @param len [in/out] Length of filename argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_INVALID_ARGUMENT if self or filename are null; ESR_BUFFER_OVERFLOW if buffer is too small
+ * to contain results
+ */
+ ESR_ReturnCode(*getFilename)(struct PFile_t* self, LCHAR* filename, size_t* len);
+
+ /**
+ * Indicates if the error-flag is set in the PFile. This functionality is provided solely
+ * for backwards-compatibility reasons with ANSI-C ferror().
+ *
+ * @param self PFile handle
+ * @param isError [out] True if the error-flag is set
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*isErrorSet)(struct PFile_t* self, ESR_BOOL* isError);
+
+ /**
+ * Clears the error-flag in the PFile. This functionality is provided solely
+ * for backwards-compatibility reasons with ANSI-C ferror().
+ *
+ * @param self PFile handle
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*clearError)(struct PFile_t* self);
+
+ /**
+ * vfprintf() implementation for PFile.
+ *
+ * @param self PFile handle
+ * @param result Function result
+ * @param format see vfprintf()
+ * @param args see vfprintf()
+ * @return see vfprintf()
+ */
+ ESR_ReturnCode(*vfprintf)(struct PFile_t* self, int* result, const LCHAR* format, va_list args);
+ /**
+ * fgetc() implementation for PFile.
+ * In case the underlying function returns an error, it will be propegated by the wrapper.
+ *
+ * @param self PFile handle
+ * @param result Function result
+ * @return see fgetc()
+ */
+ ESR_ReturnCode(*fgetc)(struct PFile_t* self, LINT* result);
+ /**
+ * fgets() implementation for PFile.
+ * In case the underlying function returns an error, it will be propegated by the wrapper.
+ *
+ * @param self PFile handle
+ * @param string See fgets()
+ * @param n See fgets()
+ * @param result Function result
+ * @return see fgets()
+ */
+ ESR_ReturnCode(*fgets)(struct PFile_t* self, LCHAR* string, int n, LCHAR** result);
+ /**
+ * Hide the memory footprint of this object from the PMemory module.
+ *
+ * NOTE: Because this function may be called by PMemory on shutdown,
+ * no PLog (which is shutdown before PMemory) functions should
+ * be used.
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*hideMemoryAllocation)(struct PFile_t* self);
+}
+PFile;
+
+#endif
+
+
+
+/*
+ * Expose functions only if use wrappers is not defined, otherwize only expose wrapper functions.
+ */
+
+#ifndef USE_LIGHT_WEIGHT_PANSI_FILE_WRAPPERS
+
+/**
+ * Closes the PFile and destroys it.
+ *
+ * @param self PFile handle
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode PFileDestroy(PFile* self);
+
+
+PORTABLE_API ESR_ReturnCode PFileOpen(PFile* self, const LCHAR* mode);
+
+/**
+ * Closes a PFile.
+ *
+ * @param self PFile handle
+ * @return ESR_CLOSE_ERROR if file cannot be closed
+ */
+PORTABLE_API ESR_ReturnCode PFileClose(PFile* self);
+
+/**
+ * Reads from a PFile.
+ *
+ * @param self PFile handle
+ * @param buffer Storage location for data
+ * @param size Item size in bytes
+ * @param count [in/out] Maximum number of items to be read. On output, contains the
+ * number of full items actually read, which may be less than count if
+ * an error occurs or if the end of the file is encountered before reaching
+ * count.
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_READ_ERROR if a reading error occurs
+ */
+PORTABLE_API ESR_ReturnCode PFileRead(PFile* self, void* buffer, size_t size, size_t* count);
+
+/**
+ * Writes data to a PFile.
+ *
+ * @param self PFile handle
+ * @param buffer Pointer to data to be written
+ * @param size Item size in bytes
+ * @param count [in/out] Maximum number of items to be read. On output, contains the
+ * number of full items actually written, which may be less than count if
+ * an error occurs.
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_WRITE_ERROR if a writing error occurs
+ */
+PORTABLE_API ESR_ReturnCode PFileWrite(PFile* self, void* buffer, size_t size, size_t* count);
+
+/**
+ * Flushes a PFile.
+ *
+ * @param self PFile handle
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_FLUSH_ERROR if a flushing error occurs
+ */
+PORTABLE_API ESR_ReturnCode PFileFlush(PFile* self);
+
+/**
+ * Flushes a PFile.
+ *
+ * @param self PFile handle
+ * @param offset Number of bytes from <code>origin</code>
+ * @param origin Initial position
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_SEEK_ERROR if a seeking error occurs
+ */
+PORTABLE_API ESR_ReturnCode PFileSeek(PFile* self, long offset, int origin);
+
+/**
+ * Gets the current position of a PFile.
+ *
+ * @param self PFile handle
+ * @param position [out] The position
+ * @return ESR_INVALID_ARGUMENT if self is null; ESR_INVALID_STATE if an internal error occurs
+ */
+PORTABLE_API ESR_ReturnCode PFileGetPosition(PFile* self, size_t* position);
+
+/**
+ * Indicates if the PFile is open.
+ *
+ * @param self PFile handle
+ * @param isOpen [out] True if file is open
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode PFileIsOpen(PFile* self, ESR_BOOL* isOpen);
+
+
+/**
+ * Indicates if the PFile is at the end of file.
+ *
+ * @param self PFile handle
+ * @param isEof [out] True if end of file has been reached
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode PFileIsEOF(PFile* self, ESR_BOOL* isEof);
+
+/**
+ * Indicates if the error-flag is set in the PFile. This functionality is provided solely
+ * for backwards-compatibility reasons with ANSI-C ferror().
+ *
+ * @param self PFile handle
+ * @param isError [out] True if the error-flag is set
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode PFileIsErrorSet(PFile* self, ESR_BOOL* isError);
+
+/**
+ * Clears the error-flag in the PFile. This functionality is provided solely
+ * for backwards-compatibility reasons with ANSI-C ferror().
+ *
+ * @param self PFile handle
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode PFileClearError(PFile* self);
+
+/**
+ * fprintf() implementation for PFile.
+ *
+ * @param self PFile handle
+ * @param result Function result
+ * @param format see fprintf()
+ * @param args see fprintf()
+ * @return see fprintf()
+ */
+PORTABLE_API ESR_ReturnCode PFileFprintf(PFile* self, int* result, const LCHAR* format, va_list args);
+
+/**
+ * vfprintf() implementation for PFile.
+ *
+ * @param self PFile handle
+ * @param result Function result
+ * @param format see vfprintf()
+ * @param args see vfprintf()
+ * @return see vfprintf()
+ */
+PORTABLE_API ESR_ReturnCode PFileVfprintf(PFile* self, int* result, const LCHAR* format, va_list args);
+/**
+ * fgetc() implementation for PFile.
+ *
+ * @param self PFile handle
+ * @param result Function result
+ * @return see fgetc()
+ */
+PORTABLE_API ESR_ReturnCode PFileFgetc(PFile* self, LINT* result);
+/**
+ * fgets() implementation for PFile.
+ *
+ * @param self PFile handle
+ * @param string See fgets()
+ * @param n See fgets()
+ * @param result Function result
+ * @return see fgets()
+ */
+PORTABLE_API ESR_ReturnCode PFileFgets(PFile* self, LCHAR* string, int n, LCHAR** result);
+
+/**
+ * Reads an integer from the PFile.
+ *
+ * @param self PFile handle
+ * @param value [out] Integer that was read
+ * @return ESR_READ_ERROR if a reading error occurs; ESR_SEEK_ERROR if a seeking error occurs;
+ * ESR_INVALID_STATE if no EOF is reached before an integer
+ */
+PORTABLE_API ESR_ReturnCode PFileReadInt(PFile* self, int* value);
+
+/**
+ * Reads a string token from the PFile.
+ *
+ * @param self PFile handle
+ * @param value [out] String that was read
+ * @param len Size of value argument.
+ * @return ESR_BUFFER_OVERFLOW if the value argument is too small; ESR_READ_ERROR if a reading error occurs;
+ * ESR_SEEK_ERROR if a seeking error occurs; ESR_INVALID_STATE if no EOF is reached before an LCHAR*
+ */
+PORTABLE_API ESR_ReturnCode PFileReadLCHAR(PFile* self, LCHAR* value, size_t len);
+
+/**
+ * Returns filename associated with PFile.
+ *
+ * @param self PFile handle
+ * @param filename [out] The filename
+ * @param len [in/out] Length of filename argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_INVALID_ARGUMENT if self or filename are null; ESR_BUFFER_OVERFLOW if buffer is too small
+ * to contain results
+ */
+PORTABLE_API ESR_ReturnCode PFileGetFilename(PFile* self, LCHAR* filename, size_t* len);
+
+#endif /* USE_LIGHT_WEIGHT_PANSI_FILE_WRAPPERS */
+
+/**
+ * Backwards compatible fopen().
+ *
+ * @param filename See fopen()
+ * @param mode See fopen()
+ * @return see fopen()
+ */
+PORTABLE_API PFile* pfopen(const LCHAR* filename, const LCHAR* mode);
+
+/**
+ * Backwards compatible fread().
+ *
+ * @param buffer See fread()
+ * @param size See fread()
+ * @param count See fread()
+ * @param stream See fread()
+ * @return see fread()
+ */
+PORTABLE_API size_t pfread(void* buffer, size_t size, size_t count, PFile* stream);
+
+/**
+ * Backwards compatible fwrite().
+ *
+ * @param buffer See fwrite()
+ * @param size See fwrite()
+ * @param count See fwrite()
+ * @param stream See fwrite()
+ * @return see fwrite()
+ */
+PORTABLE_API size_t pfwrite(void* buffer, size_t size, size_t count, PFile* stream);
+
+/**
+ * Backwards compatible fclose().
+ *
+ * @param stream See fclose()
+ * @return see fclose()
+ */
+PORTABLE_API int pfclose(PFile* stream);
+
+/**
+ * Backwards compatible rewind()
+ *
+ * @param stream See rewind()
+ * @return see rewind()
+ */
+PORTABLE_API void prewind(PFile* stream);
+
+/**
+ * Backwards compatible fseek().
+ *
+ * @param stream See fseek()
+ * @param offset See fseek()
+ * @param origin See fseek()
+ * @return see fseek()
+ */
+PORTABLE_API int pfseek(PFile* stream, long offset, int origin);
+
+/**
+ * Backwards compatible ftell().
+ *
+ * @param stream See ftell()
+ * @return see ftell()
+ */
+PORTABLE_API long pftell(PFile* stream);
+
+/**
+ * Backwards compatible fgets().
+ *
+ * @param string See fgets()
+ * @param n See fgets()
+ * @param stream See fgets()
+ * @return see fgets()
+ */
+PORTABLE_API LCHAR* pfgets(LCHAR* string, int n, PFile* stream);
+
+/**
+ * Backwards compatible feof().
+ *
+ * @param stream See feof()
+ * @return see feof()
+ */
+PORTABLE_API int pfeof(PFile* stream);
+
+/**
+ * Backwards compatible ferror().
+ *
+ * @param stream See ferror()
+ * @return see ferror()
+ */
+PORTABLE_API int pferror(PFile* stream);
+
+/**
+ * Backwards compatible clearerr().
+ *
+ * @param stream See clearerr()
+ */
+PORTABLE_API void pclearerr(PFile* stream);
+
+/**
+ * Backwards compatible fgetc().
+ *
+ * @param stream See clearerr()
+ * @return see clearerr()
+ */
+PORTABLE_API LINT pfgetc(PFile* stream);
+
+/**
+ * Backwards compatible fflush().
+ *
+ * @param stream See fflush()
+ * @return see fflush()
+ */
+PORTABLE_API int pfflush(PFile* stream);
+
+/**
+ * Backwards compatible vfprintf().
+ *
+ * @param stream See vfprintf()
+ * @param format See vfprintf()
+ * @param args See vfprintf()
+ * @return see vfprintf()
+ */
+PORTABLE_API int pvfprintf(PFile* stream, const LCHAR* format, va_list args);
+
+/**
+ * Backwards compatible fprintf().
+ *
+ * @param stream See fprintf()
+ * @param format See fprintf()
+ * @return see fprintf()
+ */
+PORTABLE_API int pfprintf(PFile* stream, const LCHAR* format, ...);
+
+/**
+ * Backwards compatible printf().
+ *
+ * @param format See printf()
+ * @return see printf()
+ */
+
+#ifndef USE_LIGHT_WEIGHT_PANSI_FILE_WRAPPERS
+PORTABLE_API int pprintf(const LCHAR* format, ...);
+#endif
+
+/*
+ * The following are only defined when using pfile wrappers.
+ */
+
+#ifdef USE_LIGHT_WEIGHT_PANSI_FILE_WRAPPERS
+PORTABLE_API ESR_ReturnCode pf_convert_backslashes_to_forwardslashes ( LCHAR *string_to_convert );
+PORTABLE_API ESR_ReturnCode pf_is_path_absolute ( const LCHAR* input_path, ESR_BOOL* isAbsolute );
+PORTABLE_API ESR_ReturnCode pf_make_dir ( const LCHAR* path );
+PORTABLE_API ESR_ReturnCode pf_get_cwd ( LCHAR* path, size_t *len );
+PORTABLE_API ESR_ReturnCode pf_change_dir ( const LCHAR* path );
+#endif
+
+/**
+ * @}
+ */
+#endif /* __PFILE_H */
diff --git a/portable/include/PFileImpl.h b/portable/include/PFileImpl.h
new file mode 100644
index 0000000..8e50514
--- /dev/null
+++ b/portable/include/PFileImpl.h
@@ -0,0 +1,82 @@
+/*---------------------------------------------------------------------------*
+ * PFileImpl.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PFILEIMPL_H
+#define __PFILEIMPL_H
+
+
+
+#include "PFile.h"
+#include "ptrd.h"
+
+/**
+ * Portable file implementation.
+ */
+typedef struct PFileImpl_t
+{
+ /**
+ * Interface functions that must be implemented.
+ */
+ PFile Interface;
+
+ /**
+ * File name relative to the file-system path.
+ */
+ LCHAR* filename;
+
+ /**
+ * True if file is in little endian format.
+ */
+ ESR_BOOL littleEndian;
+
+#ifdef USE_THREAD
+ /**
+ * Used to lock underlying file and provide atomic read/write operations.
+ */
+ PtrdMonitor* lock;
+#endif
+}
+PFileImpl;
+
+/**
+ * Initializes variables declared in the superinterface.
+ *
+ * @param self PFile handle
+ * @param filename Name of the file
+ * @param littleEndian True if file is little-endian
+ * @return ESR_OUT_OF_MEMORY if system is out of memory
+ */
+PORTABLE_API ESR_ReturnCode PFileCreateImpl(PFile* self, const LCHAR* filename, ESR_BOOL littleEndian);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PFileDestroyImpl(PFile* self);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PFileGetFilenameImpl(PFile* self, LCHAR* filename, size_t* len);
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PFileVfprintfImpl(PFile* self, int* result, const LCHAR* format, va_list args);
+
+#endif /* __PFILEIMPL_H */
diff --git a/portable/include/PFileSystem.h b/portable/include/PFileSystem.h
new file mode 100644
index 0000000..f98edab
--- /dev/null
+++ b/portable/include/PFileSystem.h
@@ -0,0 +1,225 @@
+/*---------------------------------------------------------------------------*
+ * PFileSystem.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PFILESYSTEM_H
+#define __PFILESYSTEM_H
+
+
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+#include "PFile.h"
+#include "ptypes.h"
+
+/**
+ * @addtogroup PFileSystemModule PFileSystem API functions
+ * Portable file-system API.
+ *
+ * Must call pmemInit() before using this module.
+ * If threads are to be used, ptrdInit() must be called before using this module as well.
+ *
+ * @{
+ */
+
+/**
+ * Portable standard input.
+ */
+/*PORTABLE_API PFile* PSTDIN;*/
+/**
+ * Portable standard output.
+ */
+/*PORTABLE_API PFile* PSTDOUT;*/
+/**
+ * Portable standard error.
+ */
+/*PORTABLE_API PFile* PSTDERR;*/
+
+#define PSTDIN stdin
+#define PSTDOUT stdout
+#define PSTDERR stderr
+/**
+ * Portable file-system.
+ */
+typedef struct PFileSystem_t
+{
+ /**
+ * Destroys the PFileSystem.
+ *
+ * @param self PFileSystem handle
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+ ESR_ReturnCode(*destroy)(struct PFileSystem_t* self);
+
+ /**
+ * Creates a new PFile using this file-system.
+ *
+ * @param self PFileSystem handle
+ * @param path Fully qualified file path
+ * @param littleEndian True if file is in little-endian format
+ * @param file [out] Resulting PFile
+ */
+ ESR_ReturnCode(*createPFile)(struct PFileSystem_t* self, const LCHAR* path, ESR_BOOL littleEndian, PFile** file);
+
+ /**
+ * Creates a new directory.
+ *
+ * @param self PFileSystem handle
+ * @param path Fully qualified directory path
+ * @return ESR_INVALID_ARGUMENT if path is null; ESR_IDENTIFIER_COLLISION if directory already exists;
+ * ESR_NO_MATCH_ERROR if parent directory does not exist; ESR_INVALID_STATE if an internal error occurs
+ */
+ ESR_ReturnCode(*mkdir)(struct PFileSystem_t* self, const LCHAR* path);
+
+ /**
+ * Sets the current working directory.
+ *
+ * @param self PFileSystem handle
+ * @param path Fully qualified file path
+ * @return ESR_SUCCESS if change of directory is allowed
+ */
+ ESR_ReturnCode(*chdir)(struct PFileSystem_t* self, const LCHAR* path);
+}
+PFileSystem;
+
+
+/**
+ * Initializes the portable file-system module.
+ *
+ * @return ESR_INVALID_STATE if calling StackTraceCreate() fails (see its documentation for more detail).
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemCreate(void);
+
+/**
+ * Indicates if the portable file-system module is initialized.
+ *
+ * @param isCreated [in/out] True if the module is initialized.
+ * @return ESR_INVALID_ARGUMENT if isCreated is null
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemIsCreated(ESR_BOOL* isCreated);
+
+/**
+ * Shuts down the portable file-system module.
+ *
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemDestroy(void);
+
+/**
+ * Creates a new PFile using this file-system.
+ *
+ * @param path Fully qualified file path
+ * @param littleEndian True if file is in little-endian format
+ * @param file [out] Resulting PFile
+ * @return ESR_OUT_OF_MEMORY if system is out of memory; ESR_INVALID_STATE if mutex could not be created
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemCreatePFile(const LCHAR* path, ESR_BOOL littleEndian, PFile** file);
+
+/**
+ * Indicates if path is absolute.
+ *
+ * @param path Path to be processed
+ * @param isAbsolute True if path is absolute
+ * @return ESR_INVALID_ARGUMENT if path or isAbsolute are null
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemIsAbsolutePath(const LCHAR* path, ESR_BOOL* isAbsolute);
+
+/**
+ * Returns the canonical pathname string of this abstract pathname.
+ *
+ * A canonical pathname is both absolute and unique. The precise definition of canonical
+ * form is system-dependent. This method first converts this pathname to absolute form.
+ * This typically involves removing redundant names such as "." and ".." from the pathname,
+ * resolving symbolic links (on UNIX platforms), and converting drive letters to
+ * a standard case (on Microsoft Windows platforms).
+ *
+ * POST-CONDITION: Path will contain only canonical slashes
+ *
+ * @param path Path to process
+ * @param len [in/out] Length of path argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_INVALID_ARGUMENT if path or len are null
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemGetAbsolutePath(LCHAR* path, size_t* len);
+
+/**
+ * Converts all slashes in path to '/'.
+ *
+ * @param path [in/out] Path to process
+ * @return ESR_INVALID_ARGUMENT if path is null
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemCanonicalSlashes(LCHAR* path);
+
+/**
+ * Returns parent directory of specified path.
+ * If the path ends with a filename, its directory is returned.
+ * If the path ends with a directory, its parent directory is returned.
+ *
+ * PRECONDITION: Directory names must end with '/'
+ *
+ * @param path [in/out] Path to process
+ * @param len [in/out] Length of path argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_INVALID_ARGUMENT if path or len are null; ESR_BUFFER_OVERFLOW if path is too small to contain the result
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemGetParentDirectory(LCHAR* path, size_t* len);
+
+/**
+ * Creates a new directory.
+ *
+ * @param path Directory path
+ * @return ESR_INVALID_ARGUMENT if path is null; ESR_IDENTIFIER_COLLISION if directory already exists;
+ * ESR_NO_MATCH_ERROR if parent directory does not exist; ESR_INVALID_STATE if an internal error occurs
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemMkdir(const LCHAR* path);
+
+/**
+ * Returns the current working directory (always ends with '/').
+ *
+ * @param path [out] The current working directory
+ * @param len [in/out] Length of path argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_INVALID_ARGUMENT if path or len are null; ESR_BUFFER_OVERFLOW if path is too small to contain the result
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemGetcwd(LCHAR* path, size_t* len);
+
+/**
+ * Sets the current working directory.
+ *
+ * @param path Fully qualified file path
+ * @return ESR_SUCCESS if change of directory is allowed
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemChdir(const LCHAR* path);
+
+/**
+ * Converts a linear path string to an array of path tokens.
+ * Tokens ending with a '/' denote a directory, otherwise they are a file.
+ *
+ * POST-CONDITION: The array is allocated internally, but must be freed by the caller.
+ *
+ * @param path Command-line string to parse
+ * @param tokenArray [out] The array used to hold the tokens
+ * @param count [out] The number of tokens found
+ * @return ESR_INVALID_ARGUMENT if path, tokenArray or count are null; ESR_OUT_OF_MEMORY if system is out of memory
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemLinearToPathTokens(const LCHAR* path, LCHAR*** tokenArray, size_t* count);
+
+/**
+ * @}
+ */
+#endif /* __PFILESYSTEM_H */
diff --git a/portable/include/PFileSystemImpl.h b/portable/include/PFileSystemImpl.h
new file mode 100644
index 0000000..0856867
--- /dev/null
+++ b/portable/include/PFileSystemImpl.h
@@ -0,0 +1,115 @@
+/*---------------------------------------------------------------------------*
+ * PFileSystemImpl.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PFILESYSTEMIMPL_H
+#define __PFILESYSTEMIMPL_H
+
+
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+#include "PFileSystem.h"
+#include "phashtable.h"
+
+/**
+ * Portable file-system implementation.
+ */
+typedef struct PFileSystemImpl_t
+{
+ /**
+ * Superinterface.
+ */
+ PFileSystem super;
+
+}
+PFileSystemImpl;
+
+
+/**
+ * [file path, PFileSystem*] mapping.
+ */
+PORTABLE_API PHashTable* PFileSystemPathMap;
+
+/**
+ * Current working directory.
+ */
+PORTABLE_API LCHAR PFileSystemCurrentDirectory[P_PATH_MAX];
+
+/**
+ * Default implementation.
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemDestroyImpl(PFileSystem* self);
+
+/**
+ * Initialize PSTDIN, PSTDOUT, PSTDERR.
+ *
+ * @return ESR_OUT_OF_MEMORY if system is out of memory; ESR_INVALID_STATE if mutex could not be created or if this
+ * function is called after the Ptrd module has been shut down.
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemInitializeStreamsImpl(void);
+/**
+ * Shutdown PSTDIN, PSTDOUT, PSTDERR.
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemShutdownStreamsImpl(void);
+
+/**
+ * Associates a base path with the file system.
+ *
+ * For example, if "/dev/cdrom" is specified, then any file under that path
+ * must make use of this file-system.
+ *
+ * @param basePath Base path for files associated with this filesystem
+ * @return ESR_INVALID_ARGUMENT if self or virtualPath or realPath is null or realPath is not a valid path;
+ * ESR_OUT_OF_MEMORY if the system is out of memory; ESR_IDENTIFIER_COLLISION if virtualPath is already mounted.
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemAddPathImpl(PFileSystem* self, const LCHAR* basePath);
+
+/**
+ * Deassociates the file-system from a base path.
+ *
+ * @param self PFileSystem handle
+ * @param basePath Base path for files associated with this filesystem
+ * @return ESR_INVALID_ARGUMENT if self or virtualPath is null or virtualPath is not mounted
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemRemovePathImpl(PFileSystem* self, const LCHAR* basePath);
+
+/**
+ * Given a path, returns the associated file-system and relative path.
+ *
+ * @param path Path to look up
+ * @param fileSystem [out] File-system which matches the path
+ * @param relativePath [out] Relative path associated with match. Set to NULL if this value shouldn't be returned.
+ * Otherwise, the buffer must be of size P_PATH_MAX.
+ * @return ESR_INVALID_ARGUMENT if path, fileSystem or relativePath is null; ESR_INVALID_STATE if no
+ * file-system handles the path
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemGetFS(const LCHAR* path, PFileSystem** fileSystem, LCHAR* relativePath);
+
+/**
+ * Indicates if the specified path refers to a directory. This function does not actually
+ * try resolving the path using a file-system to see if it exists. The result is based purely on the contents
+ * of the string.
+ *
+ * @param path Path to look up
+ * @param isDirectory [out] TRUE if path refers to a directory
+ * @return ESR_INVALID_ARGUMENT if path or isDirectory is null
+ */
+PORTABLE_API ESR_ReturnCode PFileSystemIsDirectoryPath(const LCHAR* path, ESR_BOOL* isDirectory);
+
+#endif /* __PFILESYSTEMIMPL_H */
diff --git a/portable/include/PStackSize.h b/portable/include/PStackSize.h
new file mode 100644
index 0000000..cd68d98
--- /dev/null
+++ b/portable/include/PStackSize.h
@@ -0,0 +1,42 @@
+/*---------------------------------------------------------------------------*
+ * PStackSize.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PSTACKSIZE_H
+#define PSTACKSIZE_H
+
+#include "PortPrefix.h"
+
+
+
+/**
+ * Initialize the stack base. This should be done in the main() function.
+ * Note that the local variables of main() are not taken into account in the
+ * stack size computation. To overcome this problem, rewrite main() as a
+ * simple function that first invokes PSTACK_SIZE_INIT and then invokes the
+ * original main().
+ */
+PORTABLE_API void PSTACK_SIZE_INIT();
+
+/**
+ * Computes the current stack size. The returned value is the number of bytes
+ * in the stack.
+ */
+PORTABLE_API size_t PSTACK_SIZE_GET();
+
+#endif
diff --git a/portable/include/PStackTrace.h b/portable/include/PStackTrace.h
new file mode 100644
index 0000000..ce9fc4a
--- /dev/null
+++ b/portable/include/PStackTrace.h
@@ -0,0 +1,111 @@
+/*---------------------------------------------------------------------------*
+ * PStackTrace.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PSTACKTRACE_H
+#define __PSTACKTRACE_H
+
+
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+
+/**
+ * @addtogroup PStackTraceModule PStackTrace API functions
+ * Manipulates process stack-trace information.
+ *
+ * @{
+ */
+
+/**
+ * Maximum length of stack-trace string.
+ */
+#define P_MAX_STACKTRACE 4096
+
+/**
+ * Maximum length of function name.
+ */
+#define P_MAX_FUNCTION_NAME 80
+
+/**
+ * Creates a new StackTrace object.
+ *
+ * @return ESR_INVALID_STATE if 1) module is already in the middle of being initialized
+ * 2) module has already been initialized by another process 3) module fails to get the current directory
+ * 4) module cannot retrieve the name of the current executing module (DLL/EXE)
+ * 5) ESR_BUFFER_OVERFLOW if an internal buffer is too small 6) module cannot retrieve the current executing module
+ * listing 7) module cannot retrieve the symbol table 8) module cannot create a new monitor
+ */
+PORTABLE_API ESR_ReturnCode PStackTraceCreate(void);
+
+/**
+ * Indicates if the PStackTrace module is initialized.
+ *
+ * @param value True if the module is initialized
+ * @return ESR_INVALID_ARGUMENT is value is null; ESR_FATAL_ERROR if locking an internal mutex fails
+ */
+PORTABLE_API ESR_ReturnCode PStackTraceIsInitialized(ESR_BOOL* value);
+
+/**
+ * Returns the depth of the current stack trace (0-based).
+ *
+ * @param depth [out] The depth
+ * @return ESR_NOT_SUPPORTED if debug symbols are missing
+ */
+PORTABLE_API ESR_ReturnCode PStackTraceGetDepth(size_t* depth);
+
+/**
+ * Returns the current process stack-track.
+ *
+ * @param text [out] The resulting stack-trace text
+ * @param len [in/out] Size of text argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_NOT_SUPPORTED if debug symbols are missing
+ */
+PORTABLE_API ESR_ReturnCode PStackTraceGetValue(LCHAR* text, size_t* len);
+
+/**
+ * Returns the current function name.
+ *
+ * @param text [out] The resulting function text
+ * @param len [in/out] Size of text argument. If the return code is ESR_BUFFER_OVERFLOW,
+ * the required length is returned in this variable.
+ * @return ESR_NOT_SUPPORTED if debug symbols are missing
+ */
+PORTABLE_API ESR_ReturnCode PStackTraceGetFunctionName(LCHAR* text, size_t* len);
+
+/**
+ * Removes the deepest level of the stack-trace.
+ *
+ * @param text [in/out] The stack-trace string.
+ * @return ESR_SUCCESS
+ */
+PORTABLE_API ESR_ReturnCode PStackTracePopLevel(LCHAR* text);
+
+/**
+ * Destroys the stack trace object.
+ *
+ * @return ESR_SUCCESS
+ */
+PORTABLE_API ESR_ReturnCode PStackTraceDestroy(void);
+
+/**
+ * @}
+ */
+
+#endif /* __PSTACKTRACE_H */
diff --git a/portable/include/PortExport.h b/portable/include/PortExport.h
new file mode 100644
index 0000000..a5a3d7e
--- /dev/null
+++ b/portable/include/PortExport.h
@@ -0,0 +1,123 @@
+/*---------------------------------------------------------------------------*
+ * PortExport.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PORT_EXPORT_H
+#define __PORT_EXPORT_H
+
+
+
+/* (1) Platform specific macro which handles symbol exports & imports.*/
+
+/* These macros are used if defining DLL import/export in the source file
+ * rather than through a .def file. */
+
+/**
+ * @addtogroup ESR_PortableModule ESR_Portable API functions
+ *
+ * @{
+ */
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+#ifdef _WIN32
+
+#ifndef HAS_INLINE
+#define HAS_INLINE
+#endif
+
+#ifdef __cplusplus
+
+#define PORT_EXPORT_DECL extern "C" __declspec(dllexport)
+#define PORT_IMPORT_DECL extern "C" __declspec(dllimport)
+
+#else /* not __cplusplus */
+
+#define PORT_EXPORT_DECL __declspec(dllexport)
+#define PORT_IMPORT_DECL __declspec(dllimport)
+#endif /* __cplusplus */
+
+#else /* not _WIN32 */
+
+#ifdef __cplusplus
+#define PORT_EXPORT_DECL extern "C"
+#define PORT_IMPORT_DECL extern "C"
+#else
+#define PORT_EXPORT_DECL extern
+#define PORT_IMPORT_DECL extern
+#endif /* __cplusplus */
+
+#endif /* _WIN32 */
+
+#if !defined(PORT_EXPORT_DECL) || !defined(PORT_IMPORT_DECL)
+#error Symbol import/export pair not defined.
+#endif
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+/* If using a .def file on win32, use these macros. */
+#ifdef __cplusplus
+
+/**
+ * Exports C-style symbols; avoids name-mangling.
+ */
+#define EXTERN extern "C"
+#else
+
+/**
+* Exports C-style symbols; avoids name-mangling.
+*/
+#define EXTERN extern
+#endif
+
+#ifdef __cplusplus
+
+/**
+ * Portable 'inline' keyword
+ */
+#define PINLINE inline
+#elif defined(_WIN32)
+
+/**
+* Portable 'inline' keyword
+*/
+#define PINLINE _inline
+#elif defined(__GNUC__)
+
+/**
+* Portable 'inline' keyword
+*/
+#ifdef __vxworks
+#define PINLINE __inline__
+#else
+#define PINLINE __inline__
+#endif
+
+#elif !defined(PINLINE)
+
+/**
+* Portable 'inline' keyword
+*/
+#define PINLINE
+#endif
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/portable/include/PortPrefix.h b/portable/include/PortPrefix.h
new file mode 100644
index 0000000..8018b27
--- /dev/null
+++ b/portable/include/PortPrefix.h
@@ -0,0 +1,33 @@
+/*---------------------------------------------------------------------------*
+ * PortPrefix.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PORTPREFIX_H
+#define PORTPREFIX_H
+
+
+
+#include "PortExport.h"
+
+#ifdef PORTABLE_EXPORTS
+#define PORTABLE_API PORT_EXPORT_DECL
+#else
+#define PORTABLE_API PORT_IMPORT_DECL
+#endif
+
+#endif
diff --git a/portable/include/pLastError.h b/portable/include/pLastError.h
new file mode 100644
index 0000000..042e2c7
--- /dev/null
+++ b/portable/include/pLastError.h
@@ -0,0 +1,37 @@
+/*---------------------------------------------------------------------------*
+ * pLastError.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PLASTERROR_H
+#define __PLASTERROR_H
+
+#include "LCHAR.h"
+#include "PortPrefix.h"
+
+#define printGetLastError(text) \
+ printGetLastErrorInternal(text, __FILE__, __LINE__)
+
+/**
+ * Retrieves a verbose error message associated with the result of GetLastError() and outputs it
+ * using PLogError (if available) or alternatively to PSTDERR.
+ *
+ * @param prefix A message to prefix the error message with.
+ */
+PORTABLE_API void printGetLastErrorInternal(const LCHAR* text, char* file, int line);
+
+#endif /* __PLASTERROR_H */
diff --git a/portable/include/passert.h b/portable/include/passert.h
new file mode 100644
index 0000000..befbcf0
--- /dev/null
+++ b/portable/include/passert.h
@@ -0,0 +1,71 @@
+/*---------------------------------------------------------------------------*
+ * passert.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PASSERT_H
+#define PASSERT_H
+
+
+
+/**
+ * @addtogroup ESR_PortableModule ESR_Portable API functions
+ *
+ * @{
+ */
+
+#if defined(_WIN32) || defined(POSIX)
+/**
+ * Checks if platform supports ASSERT.
+ */
+#define HAS_ASSERT
+#endif
+
+#if defined(HAS_ASSERT)
+
+#include <assert.h>
+
+/**
+ * Portable assert().
+ */
+#define passert(exp) assert(exp)
+
+#elif defined(NDEBUG)
+
+#define passert(exp)
+
+#else
+
+/**
+* Portable assert().
+*/
+#define passert(exp) do { \
+ if (!(exp)) \
+ { \
+ pfprintf(PSTDERR, __FILE__ "(%d): " #exp " failed.\n",__LINE__); \
+ abort(); \
+ } \
+ } \
+ while(0)
+
+#endif /* HAS_ASSERT */
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/portable/include/pcputimer.h b/portable/include/pcputimer.h
new file mode 100644
index 0000000..2a81ff0
--- /dev/null
+++ b/portable/include/pcputimer.h
@@ -0,0 +1,95 @@
+/*---------------------------------------------------------------------------*
+ * pcputimer.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PCPUTIMER_H
+#define PCPUTIMER_H
+
+
+
+#include "PortPrefix.h"
+#include "ptypes.h"
+
+/**
+ * @addtogroup PCPUTimerModule PCPUTimer API functions
+ *
+ * @{
+ */
+
+/** Typedef */
+typedef struct PCPUTimer_t PCPUTimer;
+
+/**
+ * Creates a new timer object.
+ *
+ * @param timer PCPUTimer handle
+ * @return ESR_INVALID_ARGUMENT if timer is value it points to is null
+ */
+PORTABLE_API ESR_ReturnCode PCPUTimerCreate(PCPUTimer **timer);
+
+
+/**
+ * Destroys timer object.
+ *
+ * @param timer PCPUTimer handle
+ * @return ESR_INVALID_ARGUMENT if timer is null
+ */
+PORTABLE_API ESR_ReturnCode PCPUTimerDestroy(PCPUTimer *timer);
+
+/**
+ * Starts the timer. This sets the reference time from which all new elapsed
+ * time are computed. This does not reset the elapsed time to 0. This is
+ * useful to pause the timer.
+ *
+ * @return ESR_INVALID_ARGUMENT if timer is null; ESR_FATAL_ERROR if OS timer is available
+ */
+PORTABLE_API ESR_ReturnCode PCPUTimerStart(PCPUTimer *timer);
+
+/**
+ * Stops the timer.
+ *
+ * @return ESR_INVALID_ARGUMENT if timer is null; ESR_FATAL_ERROR if OS timer is available
+ */
+PORTABLE_API ESR_ReturnCode PCPUTimerStop(PCPUTimer *timer);
+
+/**
+ * Returns the timer elapsed time. If the Timer is in the stopped state,
+ * successive calls to getElapsed() will always return the same value. If the
+ * Timer is in the started state, successive calls will return the elapsed
+ * time since the last time PCPUTimerStart() was called.
+ *
+ * @return ESR_INVALID_ARGUMENT if timer or elapsed to is null; ESR_FATAL_ERROR if OS timer is available
+ */
+PORTABLE_API ESR_ReturnCode PCPUTimerGetElapsed(PCPUTimer *timer,
+ asr_uint32_t* elapsed);
+
+/**
+ * Resets the elapsed time to 0 and resets the reference time of the Timer.
+ * This effectively reset the timer in the same state it was right after
+ * creation.
+ *
+ * @return ESR_INVALID_ARGUMENT if timer is null
+ */
+PORTABLE_API ESR_ReturnCode PCPUTimerReset(PCPUTimer *timer);
+
+/**
+ * @}
+ */
+
+
+#endif
diff --git a/portable/include/pcrc.h b/portable/include/pcrc.h
new file mode 100644
index 0000000..e82d8c3
--- /dev/null
+++ b/portable/include/pcrc.h
@@ -0,0 +1,76 @@
+/*---------------------------------------------------------------------------*
+ * pcrc.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PCRC_H
+#define PCRC_H
+
+
+
+#include "PortPrefix.h"
+#include "ptypes.h"
+
+/**
+ * @addtogroup PCRCModule PCRC API functions
+ *
+ * @{
+ */
+
+/**
+ * Computes the CRC-encoding of the block of data.
+ *
+ * @param data The data on which to compute the CRC
+ * @param size the size of the data.
+ * @return the CRC of the data.
+ */
+PORTABLE_API unsigned int pcrcComputeData(const void *data, unsigned int size);
+
+
+/**
+ * Computes the CRC-encoding of a string.
+ *
+ * @param str The string for which to compute the CRC
+ * @return the CRC of the string.
+ */
+PORTABLE_API unsigned int pcrcComputeString(const LCHAR *str);
+
+
+/**
+ * Initial value to pass to the pcrcUpdateData to ensist consistency with
+ * pcrcComputeData.
+ */
+#define CRC_INITIAL_VALUE (~0U)
+
+/**
+ * Updates the CRC when adding a new byte.
+ *
+ * @param crc The initial crc value.
+ * @param data datum to append to the crc
+ * @param size the size of the data.
+ * @return the new crc value.
+ */
+PORTABLE_API unsigned int pcrcUpdateData(unsigned int crc,
+ const void * data,
+ unsigned int size);
+
+/**
+ * @}
+ */
+
+
+#endif
diff --git a/portable/include/pendian.h b/portable/include/pendian.h
new file mode 100644
index 0000000..f92480e
--- /dev/null
+++ b/portable/include/pendian.h
@@ -0,0 +1,110 @@
+/*---------------------------------------------------------------------------*
+ * pendian.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PENDIAN_H
+#define PENDIAN_H
+
+
+
+#include "PortPrefix.h"
+#include "ptypes.h"
+
+#ifdef __sgi
+/* */#include <sys/endian.h>
+
+#elif defined(__sparc)
+/* */#include <sys/isa_defs.h>
+/* */#ifdef __LITTLE_ENDIAN
+/* *//* */#define __LITTLE_ENDIAN 1234
+/* *//* */#define __BYTE_ORDER __LITTLE_ENDIAN
+/* */#elif defined(_BIG_ENDIAN)
+/* *//* */#define __BIG_ENDIAN 4321
+/* *//* */#define __BYTE_ORDER __BIG_ENDIAN
+/* */#endif
+
+#elif defined(ANDROID)
+
+/* */#ifdef HAVE_ENDIAN
+/* */#include <endian.h>
+
+/* */#elif defined(HAVE_LITTLE_ENDIAN)
+/* *//* */#define __LITTLE_ENDIAN 1234
+/* *//* */#define __BYTE_ORDER __LITTLE_ENDIAN
+
+/* */#elif defined(HAVE_BIG_ENDIAN)
+/* *//* */#define __BIG_ENDIAN 4321
+/* *//* */#define __BYTE_ORDER __BIG_ENDIAN
+
+/* */#endif
+
+#elif defined (__linux)
+/* */#include <endian.h>
+
+#elif defined(__FreeBSD__) || defined(_decunix_)
+/* */#include <machine/endian.h>
+
+#elif defined(__i386) || defined(_M_IX86)
+/* */#undef __LITTLE_ENDIAN
+/* */#define __LITTLE_ENDIAN 1234
+/* */#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#elif defined(_sh4_)||defined(SH4)
+/* */#if defined (__vxworks)
+/* *//* */#if _BYTE_ORDER == _LITTLE_ENDIAN /* VxWorks defines _BYTE_ORDER and _LITTLE_ENDIAN */
+/* *//* *//* */#undef __LITTLE_ENDIAN
+/* *//* *//* */#define __LITTLE_ENDIAN 1234
+/* *//* *//* */#define __BYTE_ORDER __LITTLE_ENDIAN
+/* *//* */#elif _BYTE_ORDER == _BIG_ENDIAN /* VxWorks defines _BYTE_ORDER and _BIG_ENDIAN */
+/* *//* *//* */#undef __BIG_ENDIAN
+/* *//* *//* */#define __BIG_ENDIAN 4321
+/* *//* *//* */#define __BYTE_ORDER __BIG_ENDIAN
+/* *//* */#else
+/* *//* *//* */#error
+/* *//* */#endif
+/* */#else
+/* *//* */#error "Could not determine endianness of the machine Unknown OS for SH4 Chip."
+/* */#endif
+
+#else
+/* */#error "Could not determine endianness of the machine Chip Not Known."
+#endif
+
+
+/**
+ * @addtogroup ESR_PortableModule ESR_Portable API functions
+ *
+ * @{
+ */
+
+/**
+ * Swaps bytes of each item in buffer.
+ *
+ * @param buffer Buffer containing items to swap.
+ * @param count Number of items to swap.
+ * @param itemSize Size of each items.
+ */
+PORTABLE_API void swap_byte_order(void *buffer,
+ size_t count,
+ size_t itemSize);
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/portable/include/phashtable.h b/portable/include/phashtable.h
new file mode 100644
index 0000000..8e96dc5
--- /dev/null
+++ b/portable/include/phashtable.h
@@ -0,0 +1,283 @@
+/*---------------------------------------------------------------------------*
+ * phashtable.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PHASHTABLE_H
+#define PHASHTABLE_H
+
+
+
+#include "PortPrefix.h"
+#include "ptypes.h"
+#include "ESR_ReturnCode.h"
+
+/**
+ * The default initial capacity of a hash table.
+ */
+#define PHASH_TABLE_DEFAULT_CAPACITY 11
+
+/**
+ *
+ * The default maximum load factor
+ */
+#define PHASH_TABLE_DEFAULT_MAX_LOAD_FACTOR (0.75f)
+
+/**
+ * Default hash function used for hashing keys. The default function assumes
+ * the key is a 0-terminated LSTRING.
+ */
+#define PHASH_TABLE_DEFAULT_HASH_FUNCTION NULL
+
+/**
+ * Default compare function used for hashing keys. The default function
+ * assumes the key are 0-terminated LSTRING and uses LSTRCMP.
+ */
+#define PHASH_TABLE_DEFAULT_COMP_FUNCTION NULL
+
+/**
+ * @addtogroup HashTableModule HashTable API functions
+ * Abstract hash table operations. The keys of the Map are strings and values
+ * are plain void pointers. The keys and values are only stored as pointers
+ * and it is the responsibility of the user to ensure proper memory management
+ * for the keys and values.
+ *
+ * The HashTable is implemented using an array of linked lists. The capacity
+ * of the HashTable is the number of entries in this array. The load factor
+ * of the HashTable is the ratio of the total number of entries in the table
+ * vs the capacity of the table. The lower the load factor, the faster the
+ * look-up is. However, a lower load factor calls for a bigger capacity,
+ * hence it increases the memory requirement.
+ *
+ * When the load factor exceeds the maximum load factor, the capacity of the
+ * hash table is increased and each entry is put in its new linked list based
+ * on the new capacity.
+ *
+ * @{
+ */
+
+/**
+ * Signature for hashing functions.
+ */
+typedef unsigned int(*PHashFunction)(const void *key);
+
+/**
+ * Signature for comparison functions. Must return 0 if key1 is identical to
+ * key2 and non-zero otherwise. The hash function and the comparison function
+ * are related in the sense that if the comparison function for two keys
+ * return 0, then the values returned by the hash function when given these
+ * keys as arguments must be equal.
+ */
+typedef int (*PHashCompFunction)(const LCHAR *key1, const LCHAR *key2);
+
+/** Typedef */
+typedef struct PHashTable_t PHashTable;
+/** Typedef */
+typedef struct PHashTableEntry_t PHashTableEntry;
+
+/**
+ * Structure specified to specify initialization parameters for the hash
+ * table.
+ */
+typedef struct PHashTableArgs_t
+{
+ /**
+ * Total capacity.
+ */
+ size_t capacity;
+
+ /**
+ * Maximum load-factor before hashtable is rehashed.
+ */
+ float maxLoadFactor;
+
+ /**
+ * Hashing function used to compute the hashcode of a key.
+ */
+ PHashFunction hashFunction;
+
+ /**
+ * Function used to compare two keys.
+ */
+ PHashCompFunction compFunction;
+}
+PHashTableArgs;
+
+/**
+ * Creates an hash table. The hash table is created with specified capacity
+ * and maximum load factor.
+ *
+ * @param hashArgs Specifies the arguments controlling the hashtable. If
+ * NULL, all arguments are assumed to be the default value. This value is
+ * copied. This is the responsibility of the caller to delete the
+ * HashTableArgs if required.
+ *
+ * @param memTag Memory tag to be used for the internal memory allocation
+ * calls. Since this string is used by the memory allocation tag, it is not
+ * copied internally and it must remain valid for the lifetime of the hash
+ * table including the call to the HashTableDestroy function. Most likely,
+ * this string is a static string or is allocated from the stack.
+ *
+ * @param hashtable A pointer to the returned hash table. This parameter may
+ * not be NULL.
+ * @return ESR_INVALID_ARGUMENT if hashArgs, or hashTable is null or
+ * hashArgs->maxLoadFactor <= 0; ESR_OUT_OF_MEMORY if system is out of memory
+ */
+PORTABLE_API ESR_ReturnCode PHashTableCreate(PHashTableArgs *hashArgs,
+ const LCHAR *memTag,
+ PHashTable **hashtable);
+
+/**
+ * Destructor. The keys and values need to be deleted (if necessary) before
+ * deleting the table to avoid memory leak.
+ *
+ * @param ESR_INVALID_ARGUMENT if hashtable is null
+ */
+PORTABLE_API ESR_ReturnCode PHashTableDestroy(PHashTable *hashtable);
+
+/**
+ * Retrieves the size (number of entries) of the hashtable.
+ *
+ * @return ESR_INVALID_ARGUMENT if hashtable or size is null
+ */
+PORTABLE_API ESR_ReturnCode PHashTableGetSize(PHashTable *hashtable,
+ size_t *size);
+
+
+/**
+ * Retrieves the value associated with a key.
+ *
+ * @param hashtable The hashtable
+ * @param key The key for which to retrieve the value.
+ * @param value The value associated with the key.
+ * @return If no match, ESR_NO_MATCH_ERROR is returned.
+ */
+PORTABLE_API ESR_ReturnCode PHashTableGetValue(PHashTable *hashtable,
+ const void *key, void **value);
+
+/**
+ * Indicates if hashtable contains the specified key.
+ *
+ * @param hashtable The hashtable
+ * @param key The key for which to retrieve the value.
+ * @param exists [out] True if the key was found
+ * @return ESR_INVALID_ARGUMENT if self is null
+ */
+PORTABLE_API ESR_ReturnCode PHashTableContainsKey(PHashTable *hashtable,
+ const void *key, ESR_BOOL* exists);
+/**
+ * Associates a value with a key.
+ *
+ * @param hashtable The hashtable
+ *
+ * @param key The key to associate a value with.
+ *
+ * @param value The value to associate with a key.
+ *
+ * @param oldValue If this pointer is non-NULL, it will be set to the
+ * value previously associated with the key.
+ * @return ESR_INVALID_STATE if hashtable is null
+ */
+PORTABLE_API ESR_ReturnCode PHashTablePutValue(PHashTable *hashtable,
+ const void *key,
+ const void *value,
+ void **oldValue);
+
+/**
+ * Removes the value with associated with a key. Note that calling this
+ * function might cause a leak in the event that the key needs to be deleted.
+ * In those situations, use PHashTableGetEntry, then retrieve the key by
+ * PHashTableEntryGetKeyValue, destroy the key and value and then use
+ * PHashTableEntryRemove.
+ *
+ * @param hashtable The hashtable
+ * @param key The key for which to remove the associated value.
+ * @param oldValue If this pointer is non-NULL, it will be set to the value
+ * previously associated with the key and that was removed.
+ * @return ESR_INVALID_ARGUMENT if hashtable is null
+ */
+PORTABLE_API ESR_ReturnCode PHashTableRemoveValue(PHashTable *hashtable,
+ const void *key,
+ void **oldValue);
+
+/**
+ * Retrieves the hash entry corresponding to the key.
+ *
+ * @param hashtable The hashtable
+ * @param key The key for which to retrieve the hash entry.
+ * @param entry The entry associated with the key. Cannot be NULL.
+ * @return If no match, ESR_NO_MATCH_ERROR is returned.
+ */
+PORTABLE_API ESR_ReturnCode PHashTableGetEntry(PHashTable *hashtable,
+ const void *key,
+ PHashTableEntry **entry);
+
+/**
+ * Returns the key and value associated with this entry. Both key and values
+ * can be deleted after removing the entry from the table.
+ *
+ * @param entry The hashtable entry
+ * @param key If non-NULL, returns the key associated with the entry.
+ * @param value If non-NULL, returns the value associated with the entry.
+ * @return ESR_INVALID_ARGUMENT if entry is null
+ */
+PORTABLE_API ESR_ReturnCode PHashTableEntryGetKeyValue(PHashTableEntry *entry,
+ void **key,
+ void **value);
+
+/**
+ * Sets the value associated with this entry.
+ *
+ * @param entry The hashtable entry.
+ * @param value The value to associate with the entry.
+ * @param oldValue If this pointer is non-NULL, it will be set to the value
+ * previously associated with this entry.
+ */
+PORTABLE_API ESR_ReturnCode PHashTableEntrySetValue(PHashTableEntry *entry,
+ const void *value,
+ void **oldValue);
+
+/**
+ * Removes the entry from its hash table.
+ *
+ * POST-CONDITION: 'entry' variable is invalid
+ *
+ * @param entry The hashtable entry.
+ * @return ESR_INVALID_ARGUMENT if entry is null
+ */
+PORTABLE_API ESR_ReturnCode PHashTableEntryRemove(PHashTableEntry *entry);
+
+/**
+ * Resets the iterator at the beginning.
+ */
+PORTABLE_API
+ESR_ReturnCode PHashTableEntryGetFirst(PHashTable *table,
+ PHashTableEntry **entry);
+
+/**
+ * Advance to the next entry in the hash table.
+ *
+ * @param entry the current entry.
+ * @return ESR_INVALID_ARGUMENT if entry or the value it points to is null.
+ */
+PORTABLE_API ESR_ReturnCode PHashTableEntryAdvance(PHashTableEntry** entry);
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/portable/include/plog.h b/portable/include/plog.h
new file mode 100644
index 0000000..adff438
--- /dev/null
+++ b/portable/include/plog.h
@@ -0,0 +1,338 @@
+/*---------------------------------------------------------------------------*
+ * plog.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PLOG_H
+#define PLOG_H
+
+
+
+#include "ESR_ReturnCode.h"
+#include "PortPrefix.h"
+#ifdef USE_STACKTRACE
+#include "PStackTrace.h"
+#endif
+#include "passert.h"
+#include "PFileSystem.h"
+#include "ptypes.h"
+
+/**
+ * @addtogroup PLogModule PLogger API functions
+ * Logging API.
+ *
+ * Must call pmemInit() before using this module.
+ *
+ * The logging API is composed of a Logger.
+ * A Logger is an object who implements an API to actually write log messages.
+ * The logging API uses the logger when logging is to be performed but does
+ * not depend on an actual implementation of this API.
+ *
+ * When a request for logging is performed, the current level of the logging
+ * API is compared with the current stack-trace level. If the logger's log
+ * level is greater than or equal to the stack-trace level, then the
+ * message is being logged through the use of the Logger. Otherwise, the
+ * message is not logged. Setting the log level of the API to UINT_MAX is
+ * equivalent to unconditionally log all messages from all modules. Conversely,
+ * setting the log level of the API to 0 is equivalent to disabling logging globally.
+ *
+ * @{
+ */
+
+
+/**
+ * Portable logging framework.
+ */
+typedef struct PLogger_t
+{
+ /**
+ * Prints and formats a message to the log.
+ *
+ * @param self the Logger.
+ *
+ * @param format the format string specifying the next arguments (a la
+ * printf).
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error.
+ */
+ ESR_ReturnCode(*printf)(struct PLogger_t *self,
+ const LCHAR *format, ...);
+
+ /**
+ * Flushes internal buffer. This function can be left unimplemented if no
+ * buffering is performed by the logger.
+
+ * @param self the Logger
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the nature of the error.
+ */
+ ESR_ReturnCode(*flush)(struct PLogger_t *self);
+
+ /**
+ * Destroys the logger. This function is responsible to deallocate any
+ * resources used by the logger. In particular, if buffering is internally
+ * used, it needs to flush the buffer.
+ */
+ void(*destroy)(struct PLogger_t *self);
+}
+PLogger;
+
+/**
+ * Type used to control output format.
+ */
+typedef asr_uint16_t LOG_OUTPUT_FORMAT;
+
+/**
+ * Specifies that no extra information is to be output.
+ */
+#define LOG_OUTPUT_FORMAT_NONE 0x0000
+
+/**
+ * Specifies that the date and time is to be output.
+ */
+#define LOG_OUTPUT_FORMAT_DATE_TIME 0x0001
+
+/**
+ * Specifies that thread id of thread generating the message is to be output.
+ */
+#define LOG_OUTPUT_FORMAT_THREAD_ID 0x0002
+
+/**
+ * Specifies that the module name of the module generating the message is to
+ * be output.
+ */
+#define LOG_OUTPUT_FORMAT_MODULE_NAME 0x0004
+
+/**
+ * Initializes the LOG library. This function must be called before any
+ * logging can take place. PtrdInit() must be called before this function on
+ * platforms that support threads.
+ *
+ * @param logger The logger to be used to output the messages. If NULL, then
+ * logging goes to PSTDERR.
+ *
+ * @param logLevel The level of logging requested.
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error. In particular, it returns ESR_INVALID_STATE if already
+ * initialized.
+ */
+PORTABLE_API ESR_ReturnCode PLogInit(PLogger *logger, unsigned int logLevel);
+
+/**
+ * Indicates if PLog module is initialized.
+ *
+ * @param isInit True if module is initialized
+ * @return ESR_INVALID_ARGUMENT if isLocked is null
+ */
+PORTABLE_API ESR_ReturnCode PLogIsInitialized(ESR_BOOL* isInit);
+
+/**
+ * Indicates if PLog module is locked inside a critical section. This is for internal use only.
+ *
+ * @param isLocked True if module is locked
+ * @return ESR_INVALID_ARGUMENT if isLocked is null
+ */
+PORTABLE_API ESR_ReturnCode PLogIsLocked(ESR_BOOL* isLocked);
+
+/**
+ * Shutdowns the LOG library. Once this function is called, no logging
+ * activity can be performed.
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error. In particular, it returns ESR_INVALID_STATE if not
+ * initialized or already shutted down.
+ */
+PORTABLE_API ESR_ReturnCode PLogShutdown(void);
+
+/**
+ * Sets the format of the logging messages. If this function is never called,
+ * the default format is
+ *
+ * <code>LOG_OUTPUT_FORMAT_MODULE_NAME | LOG_OUTPUT_FORMAT_DATE_TIME</code>.
+ *
+ * @param format the format specification for new messages.
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error.
+ */
+PORTABLE_API ESR_ReturnCode PLogSetFormat(LOG_OUTPUT_FORMAT format);
+
+/**
+ * Gets the current log level of the LOG API.
+ *
+ * @param logLevel A pointer to where the log level is to be stored. If NULL,
+ * the function returns ESR_INVALID_ARGUMENT.
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error. In particular, it returns ESR_INVALID_STATE if the
+ * API is not initialized.
+ */
+PORTABLE_API ESR_ReturnCode PLogGetLevel(unsigned int *logLevel);
+
+
+/**
+ * Sets the current log level of the LOG API.
+ *
+ * @param logLevel The new log level.
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error. In particular, it returns ESR_INVALID_STATE if the
+ * API is not initialized.
+ */
+PORTABLE_API ESR_ReturnCode PLogSetLevel(unsigned int logLevel);
+
+/**
+ * Conditionally Logs a message. The message is logged only if module is enabled.
+ *
+ * @param msg The message format specification (ala printf).
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error. In particular, it returns ESR_INVALID_STATE if
+ * the API is not initialized.
+ */
+PORTABLE_API ESR_ReturnCode PLogMessage(const LCHAR* msg, ...);
+
+/**
+ * Unconditionally logs an error message.
+ *
+ * @param msg The message format specification (ala printf).
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error. In particular, it returns ESR_INVALID_STATE if
+ * the API is not initialized.
+ */
+PORTABLE_API ESR_ReturnCode PLogError(const LCHAR* msg, ...);
+
+
+/**
+ *
+ * Creates a logger that logs to a file.
+ *
+ * @param file The file to log to.
+ * @param logger logger handle receiving the created logger.
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error.
+ */
+PORTABLE_API ESR_ReturnCode PLogCreateFileLogger(PFile* file,
+ PLogger** logger);
+
+/**
+ * Creates a logger that logs to a circular file.
+ *
+ * @param filename The name of the file to be created.
+ * @param maxsize The maximum number of bytes that the file may have.
+ * @param logger logger handle receiving the created logger.
+ *
+ * @return ESR_SUCCESS if success, otherwise a status code indicating the
+ * nature of the error.
+ */
+PORTABLE_API ESR_ReturnCode PLogCreateCircularFileLogger(const LCHAR* filename,
+ unsigned int maxsize,
+ PLogger** logger);
+
+
+
+/**
+ * Runs a function, checks its return-code. In case of an error, logs it and jumps to
+ * the CLEANUP label.
+ */
+/* show more information for vxworks due to lack of stack trace */
+#define CHKLOG(rc, function) do { rc = (function); if (rc != ESR_SUCCESS) { PLogError("%s in %s:%d", ESR_rc2str(rc), __FILE__, __LINE__); goto CLEANUP; } } while (0)
+/**
+ * Invokes the function with args and if it is not ESR_SUCCESS, logs and
+ * returns it.
+ *
+ * @param rc Used to store the function return value
+ * @param function Function name
+ * @param args Function arguments
+ */
+#define PLOG_CHKRC_ARGS(rc, function, args) do { if((rc = (function args)) != ESR_SUCCESS) { PLogError(ESR_rc2str(rc)); return rc; } } while (0)
+
+/**
+ * Checks the function return-code and if it is not ESR_SUCCESS, logs and
+ * returns it.
+ */
+#define PLOG_CHKRC(rc, function) do { rc = (function); if (rc != ESR_SUCCESS) { PLogError(rc); return rc; } } while (0)
+
+#if defined(_DEBUG) && !defined(ENABLE_PLOG_TRACE) && ENABLE_STACKTRACE
+#define ENABLE_PLOG_TRACE
+#endif
+
+/**
+ * Macro used to have logging enabled on debug build only.
+ */
+#ifdef ENABLE_PLOG_TRACE
+
+#define PLOG_DBG_ERROR(msg) ((void) (PLogError msg))
+/**
+ * Usage: PLOG_DBG_TRACE((printf-arguments))
+ *
+ * The reason we require double brackets is to allow the use of printf-style variable
+ * argument listings in a macro.
+ */
+#define PLOG_DBG_TRACE(args) ((void) (PLogMessage args))
+#define PLOG_DBG_BLOCK(block) block
+#define PLOG_DBG_API_ENTER() \
+ do \
+ { \
+ LCHAR text[P_MAX_FUNCTION_NAME]; \
+ size_t len = P_MAX_FUNCTION_NAME; \
+ ESR_ReturnCode rc; \
+ \
+ rc = PStackTraceGetFunctionName(text, &len); \
+ if (rc==ESR_SUCCESS) \
+ PLogMessage(L("%s entered."), text); \
+ else if (rc!=ESR_NOT_SUPPORTED) \
+ pfprintf(PSTDERR, L("[%s:%d] PStackTraceGetValue failed with %s\n"), __FILE__, __LINE__, ESR_rc2str(rc)); \
+ } while (0)
+
+#define PLOG_DBG_API_EXIT(rc) \
+ \
+ do \
+ { \
+ LCHAR text[P_MAX_FUNCTION_NAME]; \
+ size_t len = P_MAX_FUNCTION_NAME; \
+ ESR_ReturnCode rc2; \
+ \
+ rc2 = PStackTraceGetFunctionName(text, &len); \
+ if (rc2==ESR_SUCCESS) \
+ PLogMessage(L("%s returned %s"), text, ESR_rc2str(rc)); \
+ else if (rc!=ESR_NOT_SUPPORTED) \
+ pfprintf(PSTDERR, "[%s:%d] PStackTraceGetValue failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc2)); \
+ } while (0)
+
+#else
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+#define PLOG_DBG_ERROR(msg) ((void) 0)
+#define PLOG_DBG_MODULE(name, logLevel)
+#define PLOG_DBG_TRACE(args) ((void) 0)
+#define PLOG_DBG_BLOCK(block)
+#define PLOG_DBG_API_ENTER() ((void) 0)
+#define PLOG_DBG_API_EXIT(rc) ((void) 0)
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+#endif /* ENABLE_PLOG_TRACE */
+
+/**
+ * @}
+ */
+
+
+#endif
diff --git a/portable/include/pmalloc.h b/portable/include/pmalloc.h
new file mode 100644
index 0000000..8bd2f21
--- /dev/null
+++ b/portable/include/pmalloc.h
@@ -0,0 +1,113 @@
+/*---------------------------------------------------------------------------*
+ * pmalloc.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+/* xalloc.h internal header */
+#ifndef _PMALLOC
+#define _PMALLOC
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef _STD
+#define _STD
+#endif
+#define _STD_BEGIN
+#define _STD_END
+
+ typedef unsigned int psize_t;
+
+#ifndef DKoffsetof
+#define DKoffsetof(T, member) ((_STD psize_t)&(((T *)0)->member))
+#endif
+
+ /* storage alignment properties */
+#define DK_AUPBND 1U /* even-byte boundaries (2^^1) */
+#define DK_ADNBND 1U
+#define DK_MEMBND 2U /* cts : 4 byte malloc boundaries (3 ==> 8 byte) */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+ _STD_BEGIN
+ /* macros */
+#define M_MASK ((1 << DK_MEMBND) - 1) /* rounds all sizes */
+#define CELL_OFF ((DKoffsetof(_Cell, _Next) + M_MASK) & ~M_MASK)
+#define SIZE_BLOCK 256 /* minimum block size, power of 2 */
+#define SIZE_CELL ((sizeof (_Cell) + M_MASK) & ~M_MASK)
+ /* type definitions */
+ typedef struct _Cell
+ {
+ psize_t _Size; /* CELL_OFF <= SIZE_CELL <= _Size */
+ struct _Cell *_Next; /* reused if CELL_OFF < SIZE_CELL */
+ }
+ _Cell;
+ typedef struct
+ {
+ _Cell **_Plast; /* null, or where to resume malloc scan */
+ _Cell *_Head; /* null, or lowest addressed free cell */
+ }
+ _Altab;
+ /* declarations */
+
+ void *_Getmem(psize_t);
+ extern _Altab _Aldata; /* free list initially empty */
+
+#if _INTELx86
+ /* #define _PTR_NORM(p) (void __huge *)(p) should have worked */
+#define _PTR_NORM(p) \
+ ( (((unsigned long)(p) & 0xFFFF0000L)>>12) \
+ + ((unsigned long)(p) & 0xFFFFL) )
+#else
+#define _PTR_NORM(p) (p)
+#endif
+
+
+#if DEBUG
+ int _OK_Cell(_Cell *p);
+ int _OK_Altab(_Altab *p);
+ void _UPD_Altab(psize_t d_heap, psize_t d_alloc, psize_t d_free);
+#else
+#define _OK_Cell(p) (void)0
+#define _OK_Altab(p) (void)0
+#define _UPD_Altab(d_heap, d_alloc, d_free) (void)0
+#endif /*DEBUG*/
+ _STD_END
+
+ /* function prototypes */
+ void PortMallocSetPoolSize(psize_t size);
+ psize_t PortMallocGetPoolSize(void);
+ int PortMallocGetMaxMemUsed(void);
+ void PortMallocInit(void);
+ void PortMallocTerm(void);
+ void *(PortMalloc)(psize_t size_arg);
+ void(PortFree)(void *ptr);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* _PMALLOC */
+
+
+
diff --git a/portable/include/pmemory.h b/portable/include/pmemory.h
new file mode 100644
index 0000000..58716ad
--- /dev/null
+++ b/portable/include/pmemory.h
@@ -0,0 +1,309 @@
+/*---------------------------------------------------------------------------*
+ * pmemory.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PMEMORY_H
+#define PMEMORY_H
+
+
+
+#define PMEM_MAP_TRACE
+
+#include "PortPrefix.h"
+#include "ptypes.h"
+#include "pstdio.h"
+#include <stddef.h>
+#include <stdlib.h>
+
+/**
+ * @addtogroup PmemoryModule PMemory API functions
+ * Library for basic memory management.
+ * Call PMemInit() to initialize and PmemShutdown() to shutdown module.
+ *
+ * @{
+ */
+
+/**
+ * Returns macro to string format.
+ */
+#define _VAL(x) #x
+/**
+ * Converts a digit to a string.
+ */
+#define _STR(x) _VAL(x)
+
+#ifdef DISABLE_MALLOC
+#define malloc #error
+#define calloc #error
+#define realloc #error
+#define free #error
+#endif
+
+#ifndef offsetof
+#define offsetof(type, member) ((size_t) &(((type *)0)->member))
+#endif
+
+/*
+ * PMEM_MAP_TRACE is not defined by default.
+ * It is up to user to define PMEM_MAP_TRACE;
+ * define in either makefile or here for test purpose.
+ */
+
+/**
+ * \<static_cast\> implementation for C.
+ */
+#define STATIC_CAST(self, subClass, member) ((subClass*) (((char*) self) - (offsetof(subClass, member))))
+
+#ifdef PMEM_MAP_TRACE
+/**
+ * Portable malloc()
+ */
+#define MALLOC(nbBytes, tag) (pmalloc(nbBytes, tag, L(__FILE__), __LINE__))
+#else
+/**
+ * Portable malloc()
+ */
+#define MALLOC(nbBytes, tag) (pmalloc(nbBytes))
+#endif
+
+#ifdef PMEM_MAP_TRACE
+/**
+ * Portable calloc()
+ */
+#define CALLOC(nbElem, elemSize, tag) (pcalloc(nbElem, elemSize , tag, L(__FILE__), __LINE__))
+#define CALLOC_CLR(nbElem, elemSize, tag) (pcalloc(nbElem, elemSize , tag, L(__FILE__), __LINE__))
+#else
+/**
+ * Portable calloc()
+ */
+#define CALLOC(nbElem, elemSize, tag) (pcalloc(nbElem, elemSize))
+#define CALLOC_CLR(nbElem, elemSize, tag) (pcalloc(nbElem, elemSize))
+#endif
+
+#ifdef PMEM_MAP_TRACE
+/**
+ * Portable realloc()
+ */
+#define REALLOC(ptr, newSize) (prealloc(ptr, newSize, L(__FILE__), __LINE__))
+#else
+/**
+ * Portable realloc()
+ */
+#define REALLOC(ptr, newSize) (prealloc(ptr, newSize))
+#endif
+
+/**
+ * Portable new()
+ */
+#define NEW(type, tag) ((type*) MALLOC(sizeof(type), tag))
+
+/**
+ * Allocates a new array
+ */
+#define NEW_ARRAY(type, nbElem, tag) ((type *) CALLOC(nbElem, sizeof(type), tag))
+
+#ifdef PMEM_MAP_TRACE
+/**
+ * Portable free()
+ */
+#define FREE(ptr) pfree(ptr, L(__FILE__), __LINE__)
+#else
+/**
+ * Portable free()
+ */
+#define FREE(ptr) pfree(ptr)
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * Allocates specified number of bytes, similar to malloc but initializes the
+ * memory to 0.
+ *
+ * @param nbBytes The number of bytes to allocate.
+ *
+ * @param tag The tag associated with the memory for reporting.
+ *
+ * @param file The file name in which the function is invoked. Should be the
+ * __FILE__ macro.
+ *
+ * @param line The line at which the function is invoked. Should be the
+ * __LINE__ macro.
+ **/
+#ifdef PMEM_MAP_TRACE
+PORTABLE_API void *pmalloc(size_t nbBytes, const LCHAR* tag, const LCHAR* file, int line);
+#else
+PORTABLE_API void *pmalloc(size_t nbBytes);
+#endif
+
+/**
+ * Allocate an array of items, similar to calloc.
+ *
+ * @param nbItems The number items to allocate.
+ *
+ * @param itemSize The size of each item.
+ *
+ * @param tag The tag associated with the memory for reporting.
+ *
+ * @param file The file name in which the function is invoked. Should be the
+ * __FILE__ macro.
+ *
+ * @param line The line at which the function is invoked. Should be the
+ * __LINE__ macro.
+ *
+ **/
+#ifdef PMEM_MAP_TRACE
+PORTABLE_API void *pcalloc(size_t nbItems, size_t itemSize, const LCHAR* tag, const LCHAR* file, int line);
+#else
+PORTABLE_API void *pcalloc(size_t nbItems, size_t itemSize);
+#endif
+
+/**
+ * Reallocates data. Similar to realloc.
+ *
+ * @param ptr A pointer previously allocated by pmalloc, pcalloc or prealloc.
+ *
+ * @param newSize The new size required.
+ *
+ * @param file The file name in which the function is invoked. Should be the
+ * __FILE__ macro.
+ *
+ * @param line The line at which the function is invoked. Should be the
+ * __LINE__ macro.
+ *
+ **/
+#ifdef PMEM_MAP_TRACE
+PORTABLE_API void *prealloc(void* ptr, size_t newSize, const LCHAR* file, int line);
+#else
+PORTABLE_API void *prealloc(void* ptr, size_t newSize);
+#endif
+
+/**
+ * Frees data allocated through pmalloc, pcalloc or realloc.
+ *
+ * @param ptr A pointer previously allocated by pmalloc, pcalloc or prealloc.
+ *
+ * @param file The file name in which the function is invoked. Should be the
+ * __FILE__ macro.
+ *
+ * @param line The line at which the function is invoked. Should be the
+ * __LINE__ macro.
+ *
+ **/
+#ifdef PMEM_MAP_TRACE
+PORTABLE_API void pfree(void* ptr, const LCHAR* file, int line);
+#else
+PORTABLE_API void pfree(void* ptr);
+#endif
+
+/**
+ * @addtogroup PmemoryModule PMemory API functions
+ * Library for basic memory management.
+ * Call PMemInit() to initialize and PmemShutdown() to shutdown module.
+ *
+ * @{
+ */
+
+/**
+ * Initializes the memory management API.
+ *
+ * @return ESR_INVALID_STATE if the PMem module is already initialized or an internal error occurs
+ */
+PORTABLE_API ESR_ReturnCode PMemInit(void);
+
+/**
+ * Shutdowns the memory management API. pmemReport is invoked with the same
+ * file that was provided to pmemInit.
+ *
+ * @return ESR_INVALID_STATE if the PMem module is not initialized
+ */
+PORTABLE_API ESR_ReturnCode PMemShutdown(void);
+
+/**
+ * Enables low-level logging to file. This logs individual memory allocations and
+ * deallocations. On shutdown, pmemDumpLogFile() will be invoked.
+ *
+ * @param file A file in which logging of memory related operations should be
+ * performed. If NULL, no logging is performed.
+ * @return ESR_INVALID_STATE if the PMem module is not initialized
+ */
+PORTABLE_API ESR_ReturnCode PMemSetLogFile(PFile* file);
+
+/**
+ * Dumps memory report to the log file, closes it and disables logging.
+ *
+ * @return ESR_INVALID_STATE if the PMem module is not initialized or an internal error occurs
+ */
+PORTABLE_API ESR_ReturnCode PMemDumpLogFile(void);
+
+/**
+ * Enables/disables memory logging. This is useful for hiding allocations/deallocation
+ * from pmemReport() and other reporting mechanisms, simply disable logging prior
+ * to hidden operations and reenable it thereafter.
+ *
+ * @param value True if logging should be enabled
+ * @return ESR_SUCCESS
+ */
+PORTABLE_API ESR_ReturnCode PMemSetLogEnabled(ESR_BOOL value);
+
+/**
+ * Hide memory allocation from pmemReport() by pretending the memory was deallocating. This is used to hide
+ * memory leaks from pmemReport(), which is useful for internal variables which are deallocated after the
+ * final call to pmemReport() occurs.
+ *
+ * @param ptr Address of memory allocation that should be hidden
+ * @return ESR_SUCCESS
+ */
+PORTABLE_API ESR_ReturnCode PMemLogFree(void* ptr);
+
+/**
+ * Generates a report of the memory allocation.
+ *
+ * @param file A file in which the report is generated. If set to NULL, the
+ * report will be generated in the same file as that was provided to pmemInit.
+ * Therefore, it is possible that no report is generated if the function is
+ * invoked with NULL and pmemInit was also invoked with NULL.
+ * @return ESR_WRITE_ERROR if an error occurs while writing to the file
+ */
+PORTABLE_API ESR_ReturnCode PMemReport(PFile* file);
+
+/**
+ * Allow user to set the memory pool size when S2G uses its own memory management.
+ * It should be called before PMemInit()
+ * The predefined (default) size is 3M for S2G
+ *
+ * @param size the memory pool size in byte
+ * @return ESR_NOT_SUPPORTED if S2G uses native memory management; ESR_INVALID_STATE if it is called after PMemInit()
+ */
+PORTABLE_API ESR_ReturnCode PMemorySetPoolSize(size_t size);
+
+/**
+ * Get the memory pool size when S2G uses its own memory management
+ *
+ * @param size the memory pool size in byte
+ * @return ESR_NOT_SUPPORTED if S2G uses native memory management
+ */
+PORTABLE_API ESR_ReturnCode PMemoryGetPoolSize(size_t *size);
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/portable/include/pmutex.h b/portable/include/pmutex.h
new file mode 100644
index 0000000..5728d3f
--- /dev/null
+++ b/portable/include/pmutex.h
@@ -0,0 +1,96 @@
+/*---------------------------------------------------------------------------*
+ * pmutex.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PMUTEX_H
+#define __PMUTEX_H
+
+#if defined(__vxworks) && !defined(REAL_PTHREADS)
+#undef USE_THREAD
+#define USE_THREAD
+#undef POSIX
+#define POSIX
+#endif
+
+
+
+#include "ESR_ReturnCode.h"
+
+#define SECOND2NSECOND 1000000000
+#define SECOND2MSECOND 1000
+#define MSECOND2NSECOND 1000000
+
+#ifdef USE_THREAD
+
+#ifdef _WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include "windows.h"
+
+typedef HANDLE MUTEX;
+typedef HANDLE EVENT;
+
+#define createMutex(mutex, locked) \
+ (*mutex = CreateMutex(NULL, locked, NULL)) == 0 ? ESR_MUTEX_CREATION_ERROR : ESR_SUCCESS
+
+#define lockMutex(mutex) waitForHandle(mutex, INFINITE)
+#define unlockMutex(mutex) (ReleaseMutex(*mutex) ? ESR_SUCCESS : ESR_FATAL_ERROR)
+#define deleteMutex(mutex) ((void) CloseHandle(*mutex))
+ESR_ReturnCode waitForHandle(HANDLE* handle, asr_uint32_t timeout);
+
+#elif defined(POSIX)
+
+#if defined(__vxworks) && !defined(REAL_PTHREADS)
+#include "pthread_vx.h"
+#else
+#include <pthread.h>
+
+#ifndef _POSIX_THREADS
+#error "Thread is not defined!"
+#endif
+#endif /* _VX_WORKS_ */
+
+typedef pthread_mutex_t MUTEX;
+typedef pthread_cond_t EVENT;
+
+ESR_ReturnCode createMutex_posix(MUTEX *mutex, ESR_BOOL locked);
+ESR_ReturnCode deleteMutex_posix(MUTEX *mutex);
+
+#define createMutex(mutex, locked) createMutex_posix(mutex, locked)
+#define deleteMutex(mutex) deleteMutex_posix(mutex)
+#define lockMutex(mutex) (pthread_mutex_lock(mutex) == 0 ? ESR_SUCCESS : ESR_FATAL_ERROR)
+#define unlockMutex(mutex) (pthread_mutex_unlock(mutex) == 0 ? ESR_SUCCESS : ESR_FATAL_ERROR)
+
+#else /* NON_POSIX */
+
+#error Portable Synchronization not defined for this OS!
+
+#endif /* _WIN32 */
+
+#else /* USE_THREAD */
+
+#define createMutex(mutex, locked) (ESR_SUCCESS)
+#define deleteMutex(mutex)
+#define lockMutex(mutex) ((void) 0)
+#define unlockMutex(mutex) ((void) 0)
+
+#endif /* USE_THREAD */
+
+#endif
diff --git a/portable/include/pstdio.h b/portable/include/pstdio.h
new file mode 100644
index 0000000..8d8f0dd
--- /dev/null
+++ b/portable/include/pstdio.h
@@ -0,0 +1,97 @@
+/*---------------------------------------------------------------------------*
+ * pstdio.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PSTDIO_H
+#define PSTDIO_H
+
+
+
+#include <stdio.h>
+#include "PortPrefix.h"
+#include "ptypes.h"
+#include "PFile.h"
+#include "ESR_ReturnCode.h"
+
+/**
+ * File table structure for memory FS
+ */
+typedef struct FileRecord_t
+{
+ /**
+ * file name
+ */
+ char name[80];
+ /**
+ * pointer to the file data
+ */
+ unsigned char *start;
+ /**
+ * real size of the file
+ */
+ int size;
+ /**
+ * total size in memory
+ */
+ int memsize;
+ /**
+ * mode: 0/1: text/binary
+ */
+ int mode;
+}
+FileRecord;
+
+#ifdef _WIN32
+
+#include "direct.h"
+#include "stdlib.h"
+
+/**
+ * @addtogroup ESR_PortableModule ESR_Portable API functions
+ *
+ * @{
+ */
+
+/**
+ * Platform-independant maximum filename path length.
+ */
+#define P_PATH_MAX _MAX_PATH
+
+/**
+ * Platform-independant maximum command-line length. In reality this value is shell-specific
+ * and is around 32k for WindowsNT however we can't spare that much stack-space and we assume
+ * such a large value will never actually occur so we settle for 4k instead.
+ */
+#define P_CMDLINE_MAX 4000
+/**
+ * @}
+ */
+
+#else
+
+#if defined(PATH_MAX)
+#define P_PATH_MAX PATH_MAX
+#elif defined(MAXPATHLEN)
+#define P_PATH_MAX MAXPATHLEN
+#else
+#error "Cannot determine value for P_PATH_MAX."
+#endif /* PATH_MAX */
+
+#endif /* _WIN32 */
+
+#endif
diff --git a/portable/include/pstream.h b/portable/include/pstream.h
new file mode 100644
index 0000000..7678640
--- /dev/null
+++ b/portable/include/pstream.h
@@ -0,0 +1,105 @@
+/*---------------------------------------------------------------------------*
+ * pstream.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#ifndef _PORTSTREAM_H_
+#define _PORTSTREAM_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include "ptypes.h"
+
+#ifdef PFILE_VIRTUAL_SUPPORT
+
+ struct FileBufferFrame;
+ typedef struct PORT_FILE_HANDLE
+ {
+ const char *filename;
+ struct FileBufferFrame *startFrame;
+ struct FileBufferFrame *endFrame;
+ struct FileBufferFrame *curFrame; /* current buffer; useful for writable file */
+ const unsigned char *curPos;
+ const unsigned char *endPos;
+ unsigned int size; /* total buffer size; useful for writable file */
+ unsigned int frame_size; /* buffer size in current frame; useful for writable file */
+ int eof;
+ int mode; /* 0 readonly text; 1 readonly binary; 2 writable text; 3 writalbe binary */
+ }
+ PORT_FILE_HANDLE;
+
+ typedef PORT_FILE_HANDLE* PORT_FILE;
+
+ typedef struct _FileRecord
+ {
+ char name[80];
+ unsigned char *start;
+ int end; /* offset of the end of the file */
+ int size; /* total buffer size */
+ int mode;
+ }
+ FileRecord;
+
+ typedef struct VirtualFileTable_t
+ {
+ const FileRecord* pFileTable;
+ const unsigned char* pFirstFile;
+ }
+ VirtualFileTable;
+
+ /* Function prototypes */
+ PORTABLE_API void PortFileInit(void);
+ PORTABLE_API PORT_FILE PortFopen(const char* filename, const char* mode);
+ PORTABLE_API int PortFclose(PORT_FILE PortFile);
+ PORTABLE_API size_t PortFread(void* buffer, size_t size, size_t count, PORT_FILE PortFile);
+ PORTABLE_API size_t PortFwrite(const void* buffer, size_t size, size_t count, PORT_FILE PortFile);
+ PORTABLE_API int PortFseek(PORT_FILE PortFile, long offset, int origin);
+ PORTABLE_API long PortFtell(PORT_FILE PortFile);
+ PORTABLE_API int PortFprintf(PORT_FILE PortFile, const char* format, ...);
+ PORTABLE_API char* PortFgets(char* string, int n, PORT_FILE PortFile);
+ PORTABLE_API int PortFflush(PORT_FILE PortFile);
+ PORTABLE_API int PortFeof(PORT_FILE PortFile);
+ PORTABLE_API int PortFgetc(PORT_FILE PortFile);
+ PORTABLE_API int PortFscanf(PORT_FILE PortFile, const char *format, ...);
+ PORTABLE_API int PortFerror(PORT_FILE PortFile);
+ PORTABLE_API void PortClearerr(PORT_FILE PortFile);
+ PORTABLE_API void PortRewind(PORT_FILE PortFile);
+ PORTABLE_API PORT_FILE PortFreopen(const char *path, const char *mode, PORT_FILE PortFile);
+ PORTABLE_API char* PortGetcwd(char *buffer, int maxlen);
+ PORTABLE_API int PortMkdir(const char *dirname);
+
+ /* this function is to create a file with the limit size */
+ PORTABLE_API int PortFcreate(const char *fname, void *pBuffer, int size);
+ PORTABLE_API void PortFdelete(const char *fname);
+
+ PORTABLE_API void PortSetFileTable(const FileRecord* pFileTable, const unsigned char* pFirstFile);
+
+ void SetFileTable(VirtualFileTable *table);
+
+#endif /* #ifdef PFILE_VIRTUAL_SUPPORT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PORTSTREAM_H */
diff --git a/portable/include/ptimer.h b/portable/include/ptimer.h
new file mode 100644
index 0000000..8aa2ee9
--- /dev/null
+++ b/portable/include/ptimer.h
@@ -0,0 +1,86 @@
+/*---------------------------------------------------------------------------*
+ * ptimer.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PTIMER_H
+#define PTIMER_H
+
+
+
+#include "PortPrefix.h"
+#include "ptypes.h"
+
+/**
+ * @addtogroup PTimerModule PTimer API functions
+ * API to facilitate computing elapsed time of operations. The units of time
+ * are milliseconds.
+ *
+ * @{
+ */
+
+/** Typedef */
+typedef struct PTimer_t PTimer;
+
+/**
+ * Creates a new timer object.
+ *
+ * @param timer PTimer handle.
+ */
+PORTABLE_API ESR_ReturnCode PTimerCreate(PTimer **timer);
+
+/**
+ * Destroys the timer object.
+ *
+ * @param timer PTimer handle.
+ */
+PORTABLE_API ESR_ReturnCode PTimerDestroy(PTimer *timer);
+
+/**
+ * Starts the timer. This sets the reference time from which all new elapsed
+ * time are computed. This does not reset the elapsed time to 0. This is
+ * useful to pause the timer.
+ **/
+PORTABLE_API ESR_ReturnCode PTimerStart(PTimer *timer);
+
+/**
+ * Stops the timer.
+ **/
+PORTABLE_API ESR_ReturnCode PTimerStop(PTimer *timer);
+
+/**
+ * Returns the timer elapsed time. If the Timer is in the stopped state,
+ * successive calls to getElapsed() will always return the same value. If the
+ * Timer is in the started state, successive calls will return the elapsed
+ * time since the last time PTimerStart() was called.
+ */
+PORTABLE_API ESR_ReturnCode PTimerGetElapsed(PTimer *timer,
+ asr_uint32_t *elapsed);
+
+/**
+ * Resets the elapsed time to 0 and resets the reference time of the Timer.
+ * This effectively reset the timer in the same state it was right after
+ * creation.
+ **/
+PORTABLE_API ESR_ReturnCode PTimerReset(PTimer *timer);
+
+/**
+ * @}
+ */
+
+
+#endif
diff --git a/portable/include/ptimestamp.h b/portable/include/ptimestamp.h
new file mode 100644
index 0000000..ec60482
--- /dev/null
+++ b/portable/include/ptimestamp.h
@@ -0,0 +1,74 @@
+/*---------------------------------------------------------------------------*
+ * ptimestamp.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PTIMESTAMP_H
+#define PTIMESTAMP_H
+
+
+
+#include <time.h>
+#include "PortPrefix.h"
+#include "ptypes.h"
+
+/**
+ * @addtogroup PTimeStampModule PTimeStamp API functions
+ *
+ * @{
+ */
+
+/**
+ * Time stamp structure with two fields: seconds and milliseconds. The secs
+ * field represent the number of seconds since January 1st 1970, 00:00:00 UTC.
+ * msecs represent the number of milliseconds within that second.
+ **/
+typedef struct PTimeStamp_t
+{
+ /**
+ * Seconds component of timestamp.
+ */
+ time_t secs;
+
+ /**
+ * Milliseconds component of timestamp.
+ */
+ asr_uint16_t msecs;
+}
+PTimeStamp;
+
+/**
+ * Sets the time stamp to represent current time. Sets both secs field and
+ * msecs field to 0 if platform does not support it.
+ **/
+PORTABLE_API void PTimeStampSet(PTimeStamp *timestamp);
+
+/**
+ * Returns the difference between two timestamps, in terms of milliseconds.
+ *
+ * @param a First timestamp
+ * @param b Second timestamp
+ * @return a - b
+ */
+PORTABLE_API int PTimeStampDiff(const PTimeStamp *a, const PTimeStamp *b);
+
+/**
+ * @}
+ */
+
+
+#endif
diff --git a/portable/include/ptrd.h b/portable/include/ptrd.h
new file mode 100644
index 0000000..eb301f1
--- /dev/null
+++ b/portable/include/ptrd.h
@@ -0,0 +1,494 @@
+/*---------------------------------------------------------------------------*
+ * ptrd.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PTRD_H
+#define PTRD_H
+
+
+
+
+#ifdef USE_THREAD
+
+#include "PortPrefix.h"
+#include "ptypes.h"
+#include "ESR_ReturnCode.h"
+
+#define STACKSIZE_S2G_SINKER 12*1024
+#define STACKSIZE_S2G_RECOGNIZER 25*1024
+#define STACKSIZE_DEFAULT 18*1024
+
+#ifdef _WIN32
+typedef unsigned int PTHREAD_ID;
+#define PtrdGetCurrentThreadId GetCurrentThreadId
+#elif defined(POSIX)
+
+#if defined(__vxworks) && !defined(REAL_PTHREADS)
+#include "pthread_vx.h"
+#else
+#include <pthread.h>
+
+#ifndef _POSIX_THREADS
+#error "Thread is not defined!"
+#endif
+#endif /* #if defined(__vxworks) && !defined(REAL_PTHREADS) */
+
+typedef pthread_t PTHREAD_ID;
+#define PtrdGetCurrentThreadId pthread_self
+#else
+#error Portable Synchronization not defined for this OS!
+#endif /* os dependant basic types */
+
+/**
+ * @addtogroup PtrdModule PThread API functions
+ * Library for basic thread and monitor functionality to ensure portability.
+ * Call PtrdInit() to initialize and PtrdShutdown() to shutdown module.
+ *
+ * Every thread has a priority. Threads with higher priority are executed in preference
+ * to threads with lower priority. When code running in some thread creates a new Thread
+ * object, the new thread has its priority initially set equal to the priority of the creating
+ * thread.
+ *
+ *
+ * @{
+ */
+
+/** Typedef */
+typedef struct PtrdMonitor_t PtrdMonitor;
+/** Typedef */
+typedef struct PtrdMutex_t PtrdMutex;
+/** Typedef */
+typedef struct PtrdSemaphore_t PtrdSemaphore;
+/** Typedef */
+typedef struct PtrdThread_t PtrdThread;
+
+
+/**
+ * Blocks the current thread for the specified amount of time.
+ *
+ * @param sleepTimeMs number of milliseconds to sleep. A value of 0 is
+ * equivalent to a thread yield.
+ *
+ * @return ESR_SUCCESS if success, or something else to indicate a failure.
+ */
+PORTABLE_API ESR_ReturnCode PtrdSleep(asr_uint32_t sleepTimeMs);
+
+/**
+ * Creates a thread monitor. Thread monitors can be locked, unlocked, can be
+ * waited on and can be notified. Monitors implement so-called recursive
+ * locking, meaning that a thread owning the monitor can call lock without
+ * blocking and will have to call unlock() as many times as lock() was called.
+ *
+ * @param monitor Handle to the created monitor
+ *
+ * @return ESR_SUCCESS if succes, or something else to indicate a failure. In
+ * particular, it will return ESR_INVALID_STATE if the threading API is not
+ * properly initialized.
+ */
+PORTABLE_API ESR_ReturnCode PtrdMonitorCreate(PtrdMonitor **monitor);
+
+/**
+ * Destroys a monitor.
+ *
+ * @param monitor Handle to the monitor to destroy
+ *
+ * @return ESR_SUCCESS if success; ESR_INVALID_STATE if this function is called after the thread
+ * library is shutdown, or cannot lock on mutex; ESR_INVALID_ARGUMENT if monitor is null
+ */
+PORTABLE_API ESR_ReturnCode PtrdMonitorDestroy(PtrdMonitor *monitor);
+
+/**
+ * Locks a monitor.
+ *
+ * @param monitor Handle to the monitor to lock
+ * @param fname Filename of code requesting a lock
+ * @param line Line of code requesting a lock
+ *
+ * @return ESR_SUCCESS if success; ESR_INVALID_ARGUMENT if monitor is null; ESR_FATAL_ERROR if waiting on the mutex failed
+ */
+PORTABLE_API ESR_ReturnCode PtrdMonitorLockWithLine(PtrdMonitor *monitor, const LCHAR *fname, int line);
+/**
+ * Locks a monitor.
+ *
+ * @param monitor Handle to the monitor to lock
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure.
+ */
+#define PtrdMonitorLock(monitor) PtrdMonitorLockWithLine(monitor, L(__FILE__), __LINE__)
+
+/**
+ * Unlock a Monitor
+ *
+ * @param monitor Handle to the monitor to unlock
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure. In particular, it will return ESR_INVALID_STATE if the current
+ * thread does not hold the monitor.
+ */
+PORTABLE_API ESR_ReturnCode PtrdMonitorUnlock(PtrdMonitor *monitor);
+
+/**
+ * Causes current thread to wait until another thread invokes the
+ * <code>PtrdMonitorNotify()</code> method or the
+ * <code>PtrdMonitorNotifyAll()</code> method for this monitor.
+ *
+ * <p>
+ *
+ * The current thread must own this monitor. The thread releases ownership of
+ * this monitor and waits until another thread notifies threads waiting on
+ * this object's monitor to wake up either through a call to the
+ * <code>PtrdMonitorNotify</code> method or the
+ * <code>PtrdMonitorNotifyAll</code> method. The thread then waits until it
+ * can re-obtain ownership of the monitor and resumes execution.
+ *
+ * @param monitor The monitor on which to wait.
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure. In particular, it will return ESR_INVALID_STATE if the current
+ * thread does not hold the monitor.
+ */
+PORTABLE_API ESR_ReturnCode PtrdMonitorWait(PtrdMonitor *monitor);
+
+
+/**
+ * Causes current thread to wait until either another thread invokes the
+ * <code>PtrdMonitorNotify()</code> method or the
+ * <code>PtrdMonitorNotifyAll()</code> method for this monitor, or a specified
+ * amount of time has elapsed.
+ *
+ * @param monitor The monitor on which to wait.
+ *
+ * @param timeoutMs The amount of time (in millisecs) to wait for
+ * notification.
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure. In particular, it will return ESR_INVALID_STATE if the current
+ * thread does not hold the monitor, or ESR_TIMED_OUT if the timeout expired
+ * without a notification.
+ */
+PORTABLE_API ESR_ReturnCode PtrdMonitorWaitTimeout(PtrdMonitor *monitor,
+ asr_uint32_t timeoutMs);
+
+/**
+ * Wakes up a single thread that is waiting on this monitor. If more than one
+ * thread are waiting on this object, one of them is arbitrarily chosen to be
+ * awakened. A thread waits on the monitor by calling
+ * <code>PtrdMonitorWait</code> or <code>PtrdMonitorWaitTimeout</code>.
+ *
+ * <p>
+ *
+ * The awakened thread will not be able to proceed until the current thread
+ * relinquishes the lock on this object. The awakened thread will compete in
+ * the usual manner with any other threads that might be actively competing to
+ * synchronize on this object; for example, the awakened thread enjoys no
+ * reliable privilege or disadvantage in being the next thread to lock this
+ * monitor.
+ *
+ * <p>
+ *
+ * This method should only be called by a thread that is the owner of this
+ * monitor.
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure. In particular, it will return ESR_INVALID_STATE if the current
+ * thread does not hold the monitor, or ESR_TIMED_OUT if the timeout expired
+ * without a notification.
+ */
+PORTABLE_API ESR_ReturnCode PtrdMonitorNotify(PtrdMonitor *monitor);
+
+/**
+ * Wakes up all threads that are waiting on this monitor. A thread waits on
+ * a monitor by calling <code>PtrdMonitorWait</code> or
+ * <code>PtrdMonitorWaitTimeout</code>
+ *
+ * <p>
+ *
+ * The awakened threads will not be able to proceed until the current thread
+ * relinquishes the monitor. The awakened threads will compete in the usual
+ * manner with any other threads that might be actively competing to
+ * synchronize on this monitor; for example, the awakened threads enjoy no
+ * reliable privilege or disadvantage in being the next thread to lock this
+ * object.
+ *
+ * <p>
+ *
+ * This method should only be called by a thread that is the owner of this
+ * object's monitor.
+ *
+ * @param monitor The monitor on which to wait.
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure. In particular, it will return ESR_INVALID_STATE if the current
+ * thread does not hold the monitor.
+ */
+PORTABLE_API ESR_ReturnCode PtrdMonitorNotifyAll(PtrdMonitor *monitor);
+
+/**
+ * Creates a thread mutex. Thread mutexes are similar to thread monitors
+ * except that they do not support wait and notify mechanism and require less
+ * resources from the OS. In situations where this mechanism is not required,
+ * using mutexes instead of monitors is preferable. Mutexes implement
+ * so-called recursive locking, meaning that a thread owning the mutex can
+ * call lock without blocking and will have to call unlock() as many times as
+ * lock() was called.
+ *
+ * @param mutex Handle to the created mutex
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure.
+ */
+PORTABLE_API ESR_ReturnCode PtrdMutexCreate(PtrdMutex **mutex);
+
+/**
+ * Destroys a mutex.
+ *
+ * @param mutex Handle to the mutex to destroy
+ *
+ * @return ESR_ReturnCode 0 on success
+ */
+PORTABLE_API ESR_ReturnCode PtrdMutexDestroy(PtrdMutex *mutex);
+
+/**
+ * Lock a mutex
+ *
+ * @param mutex Handle to the mutex to lock
+ * @param fname Filename of code requesting a lock
+ * @param line Line of code requesting a lock
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure.
+ */
+PORTABLE_API ESR_ReturnCode PtrdMutexLockWithLine(PtrdMutex *mutex, const LCHAR *fname, int line);
+/**
+ * Lock a mutex
+ *
+ * @param mutex Handle to the mutex to lock
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure.
+ */
+#define PtrdMutexLock(mutex) PtrdMutexLockWithLine(mutex, L(__FILE__), __LINE__)
+
+/**
+ * Unlock a Mutex
+ *
+ * @param mutex Handle to the mutex to unlock
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure. In particular, it will return ESR_INVALID_STATE if the current
+ * thread does not hold the mutex.
+ */
+PORTABLE_API ESR_ReturnCode PtrdMutexUnlock(PtrdMutex *mutex);
+
+
+/**
+ * Creates a thread semaphore.
+ *
+ * @param semaphore Handle to the created semaphore.
+ * @param initValue Initial semaphore value
+ * @param maxValue Maximum semaphore value
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure.
+ */
+PORTABLE_API ESR_ReturnCode PtrdSemaphoreCreate(unsigned int initValue,
+ unsigned int maxValue,
+ PtrdSemaphore **semaphore);
+
+/**
+ * Destroy a semaphore
+ *
+ * @param semaphore Handle to the semaphore to destroy
+ *
+ * @return ESR_SUCCESS if success, or an an error indicating the cause of the
+ * failure.
+ */
+PORTABLE_API ESR_ReturnCode PtrdSemaphoreDestroy(PtrdSemaphore *semaphore);
+
+/**
+ * Decrements the semaphore. If the semaphore's current value is 0, the
+ * current thread waits until the semaphore's value is greater than 0.
+ *
+ * @param semaphore Handle to the semaphore to acquire.
+ *
+ * @return ESR_SUCCESS if successful, or a status code indicating the nature of
+ * the error.
+ */
+PORTABLE_API ESR_ReturnCode PtrdSemaphoreAcquire(PtrdSemaphore *semaphore);
+
+
+/**
+ * Decrements the semaphore. If the semaphore's current value is 0, the
+ * current thread waits until the semaphore's value is greater than 0 or until
+ * the timeout expires.
+ *
+ * @param semaphore Handle to the semaphore to acquire.
+ * @param timeoutMs Timeout in milliseconds.
+ *
+ * @return ESR_SUCCESS if wait is successful, ESR_TIMED_OUT if timed out, or an
+ * error status indicating the nature of the error in other situations.
+ */
+PORTABLE_API ESR_ReturnCode PtrdSemaphoreAcquireTimeout(PtrdSemaphore *semaphore,
+ asr_uint32_t timeoutMs);
+
+/**
+ * Increments a semaphore.
+ *
+ * @param semaphore Handle to the semaphore to release.
+ *
+ * @return ESR_SUCCESS success or an error status indicating the nature of the
+ * error. In particular, it will return ESR_INVALID_STATE if the semaphore is
+ * currently at its maximum value.
+ */
+PORTABLE_API ESR_ReturnCode PtrdSemaphoreRelease(PtrdSemaphore *semaphore);
+
+
+/**
+ * Function signature invoked on the new thread by PtrdThreadCreate(), and
+ * the argument to that function.
+ */
+typedef void* PtrdThreadArg;
+/**
+ * Function prototype that launched threads must conform to.
+ *
+ * @param userData Data passed in by caller of PtrdThreadCreate
+ */
+typedef void(*PtrdThreadStartFunc)(PtrdThreadArg userData);
+
+/**
+ * Minimum thread priority.
+ */
+#define PtrdThreadMinPriority 0
+
+/**
+ * Maximum thread priority.
+ */
+#define PtrdThreadMaxPriority UINT16_TMAX
+
+/**
+ * Normal thread priority.
+ */
+#define PtrdThreadNormalPriority (PtrdThreadMaxPriority / 2)
+
+/**
+ * Creates a thread.
+ *
+ * Execution starts on the thread immediately. To pause execution use a
+ * monitor or a mutex between the thread and the thread creator.
+ *
+ * @param thread Handle to the thread that is created
+ * @param startFunc Function for the thread to start execution on
+ * @param arg Argument to the thread function
+ *
+ * @return ESR_INVALID_ARGUMENT if thread or startFunc are null; ESR_OUT_OF_MEMORY if system is out of memory;
+ * ESR_THREAD_CREATION_ERROR if thread cannot be created
+ */
+PORTABLE_API ESR_ReturnCode PtrdThreadCreate(PtrdThreadStartFunc startFunc, PtrdThreadArg arg,
+ PtrdThread** thread);
+
+/**
+ * Destroys a thread handle.
+ *
+ * Note: this does NOT stop or destroy the thread, it just releases
+ * the handle for accessing it. If this is not done, a memory leak
+ * occurs, so if the creator of the thread never needs to communicate
+ * with the thread again it should call this immediately after the
+ * create if the create was successful.
+ *
+ * @return ESR_SUCCESS on failure or an error indicating the nature of the
+ * error.
+ */
+PORTABLE_API ESR_ReturnCode PtrdThreadDestroy(PtrdThread *thread);
+
+/**
+ * Wait for the termination of a specified thread
+ *
+ * @param thread Handle to the thread to wait for
+ *
+ * @return ESR_INVALID_ARGUMENT if thread is null
+ */
+PORTABLE_API ESR_ReturnCode PtrdThreadJoin(PtrdThread *thread);
+
+/**
+ * Returns the thread priority.
+ *
+ * @param thread PtrdThread handle
+ * @param value [out] Thread priority
+ *
+ * @return ESR_INVALID_ARGUMENT if thread or value are null; ESR_INVALID_STATE if thread priority cannot be
+ * retrieved
+ */
+PORTABLE_API ESR_ReturnCode PtrdThreadGetPriority(PtrdThread *thread, asr_uint16_t* value);
+
+/**
+ * Sets the thread priority.
+ *
+ * @param thread PtrdThread handle
+ * @param value Thread priority
+ *
+ * @return ESR_INVALID_ARGUMENT if thread or value are null; ESR_INVALID_STATE if thread priority cannot be
+ * set
+ */
+PORTABLE_API ESR_ReturnCode PtrdThreadSetPriority(PtrdThread *thread, asr_uint16_t value);
+
+/**
+ * Yields execution of the current thread to other threads.
+ *
+ * @return ESR_SUCCESS
+ */
+PORTABLE_API ESR_ReturnCode PtrdThreadYield(void);
+
+/**
+ * Initializes the thread library. This should be called before creating the
+ * first thread or the first monitor.
+ *
+ * @return ESR_INVALID_STATE if the Ptrd module has already been initialized;
+ * ESR_MUTEX_CREATION_ERROR if mutex cannot be created
+ */
+PORTABLE_API ESR_ReturnCode PtrdInit(void);
+
+/**
+ * Indicates if thread library has been initialized.
+ *
+ * @param enabled [out] True if library is initialized
+ * @return ESR_INVALID_ARGUMENT if enabled is null
+ */
+PORTABLE_API ESR_ReturnCode PtrdIsEnabled(ESR_BOOL* enabled);
+
+/**
+ * Shutdowns the thread library. All thread and monitor should be terminated
+ * and destroyed before calling this function.
+ *
+ * @return ESR_INVALID_STATE if Ptrd module is not running
+ * error.
+ */
+PORTABLE_API ESR_ReturnCode PtrdShutdown(void);
+
+/**
+ * @}
+ */
+
+#else
+
+
+//#error "Including ptrd.h on a non-threaded platform."
+
+
+#endif /* USE_THREAD */
+#endif
diff --git a/portable/include/ptstutils.h b/portable/include/ptstutils.h
new file mode 100644
index 0000000..dc7ca19
--- /dev/null
+++ b/portable/include/ptstutils.h
@@ -0,0 +1,65 @@
+/*---------------------------------------------------------------------------*
+ * ptstutils.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef PTSTUTILS_H
+#define PTSTUTILS_H
+
+
+
+#include "pstdio.h"
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+/**
+ * Macros defined to facilitate the writing of test programs.
+ * That's why they are not dependent on any compile-time flag.
+ */
+#define ASSERT(x) \
+ do { \
+ if (!(x)) \
+ { \
+ pfprintf(PSTDERR, L(__FILE__ "(%d): " #x " failed: aborting.\n"), __LINE__); \
+ exit(-1); \
+ } \
+ } \
+ while(0)
+
+#define ESR_ASSERT(x) \
+ do { \
+ if ((x) != ESR_SUCCESS) \
+ { \
+ pfprintf(PSTDERR, L(__FILE__ "(%d): " #x " failed: aborting.\n"), __LINE__); \
+ exit(-1); \
+ } \
+ } \
+ while(0)
+
+#define ASSERT2(x, count) \
+ do { \
+ if (!(x)) \
+ { \
+ pfprintf(PSTDERR, L(__FILE__ "(%d): " #x " failed.\n"), __LINE__); \
+ ++count; \
+ } \
+ } \
+ while(0)
+
+#endif
diff --git a/portable/include/ptypes.h b/portable/include/ptypes.h
new file mode 100644
index 0000000..40352c0
--- /dev/null
+++ b/portable/include/ptypes.h
@@ -0,0 +1,494 @@
+/*---------------------------------------------------------------------------*
+ * ptypes.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#ifndef __PTYPES_H
+#define __PTYPES_H
+
+
+
+#include <string.h>
+#include <ctype.h>
+#include "limits.h"
+#include "PortPrefix.h"
+
+#ifndef MAX
+#define MAX(A,B) ((A)>(B)?(A):(B))
+#endif
+#ifndef MIN
+#define MIN(A,B) ((A)<(B)?(A):(B))
+#endif
+
+
+/**
+ * Boolean definition.
+ */
+typedef enum ESR_BOOL
+{
+ ESR_FALSE = 0,
+ ESR_TRUE = 1
+} ESR_BOOL;
+
+/**
+ * @addtogroup ESR_PortableModule ESR_Portable API functions
+ *
+ * @{
+ */
+
+#ifdef _WIN32
+
+#pragma warning (disable: 4100 4127)
+#pragma warning (error: 4133 4020)
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+/**
+ * Portable 32-bit unsigned integer.
+ */
+typedef unsigned int asr_uint32_t;
+
+/**
+ * Portable 32-bit signed integer.
+ */
+typedef int asr_int32_t;
+
+/**
+ * Portable 16-bit unsigned integer.
+ */
+typedef unsigned short asr_uint16_t;
+
+/**
+ * Portable 16-bit signed integer.
+ */
+typedef short asr_int16_t;
+
+/**
+ * Portable 8-bit unsigned integer.
+ */
+typedef unsigned char asr_uint8_t;
+
+/**
+ * Portable 8-bit signed integer.
+ */
+typedef signed char asr_int8_t;
+
+#else
+
+
+/**
+ * Portable 32-bit unsigned integer.
+ */
+typedef unsigned int asr_uint32_t;
+
+/**
+ * Portable 32-bit signed integer.
+ */
+typedef int asr_int32_t;
+
+/**
+ * Portable 16-bit unsigned integer.
+ */
+typedef unsigned short asr_uint16_t;
+
+/**
+ * Portable 16-bit signed integer.
+ */
+typedef short asr_int16_t;
+
+/**
+ * Portable 8-bit unsigned integer.
+ */
+typedef unsigned char asr_uint8_t;
+
+/**
+ * Portable 8-bit signed integer.
+ */
+typedef signed char asr_int8_t;
+
+///**
+// * Boolean definition.
+// */
+//#ifdef __vxworks
+///* VxWorks defines BOOL as: typedef int BOOL in vxTypesOld.h */
+//#include <vxWorks.h>
+//#define FALSE 0
+//#define TRUE 1
+//#endif
+
+#ifdef _solaris_
+#include <sys/int_types.h>
+#elif defined(_decunix_)
+#include <inttypes.h>
+#elif defined(POSIX)
+
+#include <time.h>
+#include <errno.h>
+
+#if (CPU != SIMNT)
+typedef void * HANDLE;
+#endif /* (CPU != SIMNT) */
+
+#if defined(__vxworks) /* VxWorks */
+#include <sys/times.h>
+#include <types.h>
+/* VxWorks does not support recursive mutex in POSIX.4 */
+#define OS_NO_RECURSIVE_MUTEX_SUPPORT
+#elif defined(_QNX_) /* QNX */
+#include <sys/time.h>
+#include <inttypes.h>
+#elif (OS == OS_UNIX)
+#include <string.h>
+#include <pthread.h>
+#else
+#error "New OS support here"
+#endif
+
+#ifndef _POSIX_SOURCE
+#define _POSIX_SOURCE
+#endif
+
+/* Both POSIX.1 and POSIX.4 (POSIX1003.1c) are supported */
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 199309
+#endif
+
+#include <unistd.h>
+/*
+#ifndef _POSIX_VERSION
+#error "POSIX is not supported!")
+#elif _POSIX_VERSION == 199009
+#pragma message("POSIX.1 is supported only")
+#elif _POSIX_VERSION == 199309
+#pragma message("POSIX.1 and POSIX.4 are supported")
+#elif _POSIX_VERSION > 199309
+#pragma message("Version is newer than POSIX.4")
+#endif // _POSIX_VERSION
+*/
+#else
+/* Linux, maybe others too */
+#endif
+#endif
+
+/**
+ * Minimum value of UINT16_T.
+ */
+#define UINT16_TMIN 0
+
+/**
+ * Maximum value of UINT16_T.
+ */
+#define UINT16_TMAX 65535
+
+/*
+ * These should be platform-dependent. But for the moment, we will assume
+ * narrow character.
+ */
+#ifndef USE_NARROW_CHAR
+#define USE_NARROW_CHAR
+#endif
+
+#ifdef USE_NARROW_CHAR
+/**
+ * Locale-independant character.
+ */
+typedef char LCHAR;
+
+/**
+ * Locale-independant integer-representation of a character. Used by fgetc() and others.
+ */
+typedef int LINT;
+
+/**
+ * LCHAR version of string-constant
+ */
+#define L(x) x
+
+/**
+ * LCHAR version of strcat()
+ */
+#define LSTRCAT strcat
+
+/**
+ * LCHAR version of strchr()
+ */
+#define LSTRCHR strchr
+
+/**
+ * LCHAR version of strrchr()
+ */
+#define LSTRRCHR strrchr
+
+/**
+ * LCHAR version of strcmp()
+ */
+#define LSTRCMP strcmp
+
+/**
+ * LCHAR version of strncmp()
+ */
+#define LSTRNCMP strncmp
+
+/**
+ * LCHAR version of strcpy()
+ */
+#define LSTRCPY strcpy
+
+/**
+ * LCHAR version of strftime()
+ */
+#define LSTRFTIME strftime
+
+/**
+ * LCHAR version of strlen()
+ */
+#define LSTRLEN strlen
+
+/**
+ * LCHAR version of strncpy()
+ */
+#define LSTRNCPY strncpy
+
+/**
+ * LCHAR version of memmove()
+ */
+#define LMEMMOVE memmove
+
+/**
+ * LCHAR version of strstr()
+ */
+#define LSTRSTR strstr
+
+/**
+ * LCHAR version of strlwr() which converts a string to lowercase.
+ */
+#define LSTRLWR lstrlwr
+
+/**
+ * LCHAR version of strupr() which converts a string to lowercase.
+ */
+#define LSTRUPR lstrupr
+
+/**
+ * LCHAR version of strtod()
+ */
+#define LSTRTOD strtod
+
+/**
+ * LCHAR version of strtol()
+ */
+#define LSTRTOL strtol
+
+/**
+ * LCHAR version of strtoul()
+ */
+#define LSTRTOUL strtoul
+
+/**
+ * LCHAR version of isspace()
+ */
+#define LISSPACE(c) isspace((unsigned char) c)
+
+/**
+ * LCHAR version of strcspn()
+ */
+#define LSTRCSPN strcspn
+
+/**
+ * LCHAR version of isalpha()
+ */
+#define LISALPHA isalpha
+
+/**
+ * LCHAR version of isalnum()
+ */
+#define LISALNUM isalnum
+
+/**
+ * LCHAR version of isdigit()
+ */
+#define LISDIGIT isdigit
+
+/**
+ * LCHAR version of strtok()
+ */
+#define LSTRTOK strtok
+
+/**
+ * LCHAR version of getenv()
+ */
+#define LGETENV getenv
+
+/**
+ * Converts LCHAR character to uppercase.
+ */
+#define LTOUPPER toupper
+
+/**
+ * Converts LCHAR character to lowercase.
+ */
+#define LTOLOWER tolower
+
+/**
+ * Portable printf().
+ */
+#define LPRINTF printf
+/**
+ * Portable fprintf().
+ */
+#define LFPRINTF fprintf
+/**
+ * Portable sprintf().
+ */
+#define LSPRINTF sprintf
+
+/**
+ * Portable sprintf().
+ */
+#define psprintf sprintf
+
+/**
+ * Portable svprintf().
+ */
+#define pvsprintf vsprintf
+
+#else
+
+#include <wchar.h>
+typedef wchar_t LCHAR;
+/**
+* Locale-independant integer-representation of a character. Used by fgetc() and others.
+*/
+typedef wint_t LINT;
+#define L(x) L ## x
+#define LSTRCAT wcscat
+#define LSTRCHR wcschr
+#define LSTRRCHR wcsrchr
+#define LSTRCMP wcscmp
+#define LSTRNCMP wcsncmp
+#define LSTRCPY wcscpy
+#define LSTRFTIME wcsftime
+
+#define LPRINTF wprintf
+#define LFPRINTF fwprintf
+#define LSPRINTF swprintf
+
+#ifdef _WIN32
+
+/**
+* LCHAR version of getenv()
+*/
+#define LGETENV wgetenv
+
+/**
+* LCHAR version of strlwr() which converts a string to lowercase.
+*/
+#define LSTRLWR _wcslwr
+
+/**
+* LCHAR version of strtok()
+*/
+#define LSTRTOK wcstok
+
+/**
+* LCHAR version of strupr() which converts a string to lowercase.
+*/
+#define LSTRUPR _wcsupr
+#else
+#define LSTRCASECMP wcscasecmp
+#define LSTRLWR #error LSTRLWR not defined.
+#define LSTRUPR #error LSTRUPR not defined.
+#endif /* _WIN32 */
+
+#define LSTRLEN wcslen
+#define LSTRNCPY wcsncpy
+#define LMEMMOVE wmemmove
+#define LSTRSTR wcsstr
+#define LSTRTOD wcstod
+#define LSTRTOL wcstol
+#define LSTRTOUL wcstoul
+#define LISSPACE iswspace
+#define LSTRCSPN wcscspn
+#define LISALPHA iswalpha
+#define LISALNUM iswalnum
+#define LISDIGIT iswdigit
+
+/**
+* Converts LCHAR character to uppercase.
+*/
+#define LTOUPPER towupper
+
+/**
+* Converts LCHAR character to lowercase.
+*/
+#define LTOLOWER towlower
+
+/**
+* Portable sprintf().
+*/
+#define psprintf sprintf
+
+/**
+* Portable svprintf().
+*/
+#define pvsprintf vsprintf
+
+#endif /* USE_NARROW_CHAR */
+
+/**
+ * Log of 2 in base 10.
+ */
+#define LOG_10_2 (0.30102999566398)
+
+
+/**
+ * Maximum number of digits used to represent an unsigned int as a string in
+ * base 10. The +1 is for taking into account the fact that the fractional
+ * part is removed and that we really need to take the ceiling.
+ */
+#define MAX_UINT_DIGITS ((size_t) ((CHAR_BIT * sizeof(int) * LOG_10_2) + 1))
+
+/**
+ * Maximum number of digits used to represent an int as a string in base 10.
+ * +1 for sign character [+, -]
+ */
+#define MAX_INT_DIGITS ((size_t) (MAX_UINT_DIGITS + 1))
+
+/**
+ * Indicates if text contains a number (and nothing else).
+ *
+ * @param text String to check
+ * @return ESR_TRUE if text is a number, ESR_FALSE otherwise.
+ */
+PORTABLE_API ESR_BOOL isNumber(const LCHAR* text);
+
+/**
+ * @}
+ */
+
+
+#include "ESR_ReturnCode.h"
+
+
+#include "pstdio.h"
+
+#endif
+
+
diff --git a/portable/src/ArrayList.c b/portable/src/ArrayList.c
new file mode 100644
index 0000000..4c1127b
--- /dev/null
+++ b/portable/src/ArrayList.c
@@ -0,0 +1,132 @@
+/*---------------------------------------------------------------------------*
+ * ArrayList.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#include "ArrayList.h"
+#include "plog.h"
+#include "pmemory.h"
+
+
+ESR_ReturnCode ArrayListAdd(ArrayList* self, void* element)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->add(self, element);
+}
+
+ESR_ReturnCode ArrayListInsertAt(ArrayList* self, size_t index, void* element)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->insertAt(self, index, element);
+}
+
+ESR_ReturnCode ArrayListRemove(ArrayList* self, void* element)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->remove(self, element);
+}
+
+ESR_ReturnCode ArrayListRemoveAtIndex(ArrayList* self, size_t index)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->removeAtIndex(self, index);
+}
+
+ESR_ReturnCode ArrayListRemoveAll(ArrayList* self)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->removeAll(self);
+}
+
+ESR_ReturnCode ArrayListContains(ArrayList* self, void* element, ESR_BOOL* exists)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->contains(self, element, exists);
+}
+
+ESR_ReturnCode ArrayListGetSize(ArrayList* self, size_t* size)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->getSize(self, size);
+}
+
+ESR_ReturnCode ArrayListGet(ArrayList* self, size_t index, void** element)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->get(self, index, element);
+}
+
+ESR_ReturnCode ArrayListSet(ArrayList* self, size_t index, void* element)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->set(self, index, element);
+}
+
+ESR_ReturnCode ArrayListClone(ArrayList* self, ArrayList* clone)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->clone(self, clone);
+}
+
+ESR_ReturnCode ArrayListDestroy(ArrayList* self)
+{
+ if (self == NULL)
+ return ESR_INVALID_ARGUMENT;
+ return self->destroy(self);
+}
diff --git a/portable/src/ArrayListImpl.c b/portable/src/ArrayListImpl.c
new file mode 100644
index 0000000..0451e9c
--- /dev/null
+++ b/portable/src/ArrayListImpl.c
@@ -0,0 +1,241 @@
+/*---------------------------------------------------------------------------*
+ * ArrayListImpl.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#include "ArrayList.h"
+#include "ArrayListImpl.h"
+#include "pmemory.h"
+
+#define MTAG NULL
+#define INITIAL_CAPACITY 16
+
+ESR_ReturnCode ArrayListCreateWithCapacity(ArrayList **self, size_t minCapacity)
+{
+ ArrayListImpl* impl;
+
+ if (self == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ impl = NEW(ArrayListImpl, MTAG);
+
+ if (impl == NULL)
+ return ESR_OUT_OF_MEMORY;
+
+ impl->Interface.add = &ArrayList_Add;
+ impl->Interface.insertAt = &ArrayList_InsertAt;
+ impl->Interface.contains = &ArrayList_Contains;
+ impl->Interface.destroy = &ArrayList_Destroy;
+ impl->Interface.get = &ArrayList_Get;
+ impl->Interface.getSize = &ArrayList_GetSize;
+ impl->Interface.remove = &ArrayList_Remove;
+ impl->Interface.removeAtIndex = &ArrayList_RemoveAtIndex;
+ impl->Interface.removeAll = &ArrayList_RemoveAll;
+ impl->Interface.set = &ArrayList_Set;
+ impl->Interface.toStaticArray = NULL; /* Not implemented */
+ impl->Interface.clone = &ArrayList_Clone;
+
+ impl->contents = MALLOC(minCapacity * sizeof(void*), MTAG);
+ if (impl->contents == NULL)
+ {
+ FREE(impl);
+ return ESR_OUT_OF_MEMORY;
+ }
+ impl->capacity = minCapacity;
+ impl->minCapacity = minCapacity;
+ impl->size = 0;
+
+ *self = (ArrayList*) impl;
+ return ESR_SUCCESS;
+}
+
+
+ESR_ReturnCode ArrayListCreate(ArrayList** self)
+{
+ return ArrayListCreateWithCapacity(self, INITIAL_CAPACITY);
+}
+
+static ESR_ReturnCode ArrayList_Insert_Internal(ArrayListImpl *impl, size_t index, void *element)
+{
+ size_t i;
+
+ if (impl->size >= impl->capacity)
+ {
+ /* enlarge buffer */
+ size_t newCapacity = impl->capacity * 2;
+ void** temp = REALLOC(impl->contents, newCapacity * sizeof(void*));
+ if (temp == NULL)
+ return ESR_OUT_OF_MEMORY;
+ impl->contents = temp;
+ impl->capacity = newCapacity;
+ }
+
+ for (i = impl->size; i > index; --i)
+ impl->contents[i] = impl->contents[i - 1];
+ ++impl->size;
+ impl->contents[index] = element;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode ArrayList_Add(ArrayList* self, void* element)
+{
+ ArrayListImpl *impl = (ArrayListImpl *) self;
+
+ return ArrayList_Insert_Internal(impl, impl->size, element);
+}
+
+ESR_ReturnCode ArrayList_InsertAt(ArrayList *self, size_t index, void *element)
+{
+ ArrayListImpl *impl = (ArrayListImpl *) self;
+
+ if (index > impl->size)
+ return ESR_ARGUMENT_OUT_OF_BOUNDS;
+
+ return ArrayList_Insert_Internal(impl, index, element);
+}
+
+static ESR_ReturnCode ArrayList_Remove_Internal(ArrayListImpl *impl, size_t i)
+{
+ --impl->size;
+ while (i < impl->size)
+ {
+ impl->contents[i] = impl->contents[i+1];
+ ++i;
+ }
+
+ if (impl->capacity > impl->minCapacity &&
+ impl->size <= impl->capacity / 4)
+ {
+ void** temp;
+ size_t newCapacity = impl->capacity / 2;
+
+ /* shrink buffer */
+ if ((temp = REALLOC(impl->contents, newCapacity * sizeof(void*))) == NULL)
+ return ESR_OUT_OF_MEMORY;
+ impl->contents = temp;
+ impl->capacity = newCapacity;
+ }
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode ArrayList_Remove(ArrayList* self, const void* element)
+{
+ ArrayListImpl* impl = (ArrayListImpl*) self;
+ size_t i;
+
+ /* Remove element */
+ for (i = 0; i < impl->size; ++i)
+ {
+ if (impl->contents[i] == element)
+ return ArrayList_Remove_Internal(impl, i);
+ }
+
+ return ESR_NO_MATCH_ERROR;
+}
+
+ESR_ReturnCode ArrayList_RemoveAtIndex(ArrayList* self, size_t index)
+{
+ ArrayListImpl* impl = (ArrayListImpl*) self;
+
+ if (index >= impl->size)
+ return ESR_ARGUMENT_OUT_OF_BOUNDS;
+
+ return ArrayList_Remove_Internal(impl, index);
+}
+
+ESR_ReturnCode ArrayList_RemoveAll(ArrayList* self)
+{
+ ArrayListImpl* impl = (ArrayListImpl*) self;
+
+ impl->size = 0;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode ArrayList_Contains(ArrayList* self, const void* element,
+ ESR_BOOL* exists)
+{
+ ArrayListImpl* impl = (ArrayListImpl*) self;
+ size_t i;
+
+ for (i = 0; i < impl->size; ++i)
+ {
+ if (impl->contents[i] == element)
+ {
+ *exists = ESR_TRUE;
+ return ESR_SUCCESS;
+ }
+ }
+ *exists = ESR_FALSE;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode ArrayList_Get(ArrayList* self, size_t index, void** element)
+{
+ ArrayListImpl* impl = (ArrayListImpl*) self;
+
+ if (index >= impl->size)
+ return ESR_ARGUMENT_OUT_OF_BOUNDS;
+ *element = impl->contents[index];
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode ArrayList_Set(ArrayList* self, size_t index, void* element)
+{
+ ArrayListImpl* impl = (ArrayListImpl*) self;
+
+ if (index >= impl->size)
+ return ESR_ARGUMENT_OUT_OF_BOUNDS;
+ impl->contents[index] = element;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode ArrayList_GetSize(ArrayList* self, size_t* size)
+{
+ ArrayListImpl* impl = (ArrayListImpl*) self;
+
+ *size = impl->size;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode ArrayList_Clone(ArrayList* self, ArrayList* clone)
+{
+ size_t size, i;
+ void* element;
+ ESR_ReturnCode rc;
+
+ CHK(rc, clone->removeAll(clone));
+ CHK(rc, self->getSize(self, &size));
+ for (i = 0; i < size; ++i)
+ {
+ CHK(rc, self->get(self, i, &element));
+ CHK(rc, clone->add(clone, element));
+ }
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode ArrayList_Destroy(ArrayList* self)
+{
+ ArrayListImpl* impl = (ArrayListImpl*) self;
+
+ FREE(impl->contents);
+ FREE(self);
+ return ESR_SUCCESS;
+}
diff --git a/portable/src/ESR_ReturnCode.c b/portable/src/ESR_ReturnCode.c
new file mode 100644
index 0000000..539ff24
--- /dev/null
+++ b/portable/src/ESR_ReturnCode.c
@@ -0,0 +1,143 @@
+/*---------------------------------------------------------------------------*
+ * ESR_ReturnCode.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#include "ESR_ReturnCode.h"
+
+#define RETURNCODE_COUNT 28
+static LCHAR* rcStringMapping[RETURNCODE_COUNT+1] =
+ {
+ L("ESR_SUCCESS"),
+ L("ESR_CONTINUE_PROCESSING"),
+ L("ESR_FATAL_ERROR"),
+ L("ESR_BUFFER_OVERFLOW"),
+ L("ESR_OPEN_ERROR"),
+ L("ESR_ALREADY_OPEN"),
+ L("ESR_CLOSE_ERROR"),
+ L("ESR_ALREADY_CLOSED"),
+ L("ESR_READ_ERROR"),
+ L("ESR_WRITE_ERROR"),
+ L("ESR_FLUSH_ERROR"),
+ L("ESR_SEEK_ERROR"),
+ L("ESR_OUT_OF_MEMORY"),
+ L("ESR_ARGUMENT_OUT_OF_BOUNDS"),
+ L("ESR_NO_MATCH_ERROR"),
+ L("ESR_INVALID_ARGUMENT"),
+ L("ESR_NOT_SUPPORTED"),
+ L("ESR_INVALID_STATE"),
+ L("ESR_THREAD_CREATION_ERROR"),
+ L("ESR_IDENTIFIER_COLLISION"),
+ L("ESR_TIMED_OUT"),
+ L("ESR_INVALID_RESULT_TYPE"),
+ L("ESR_NOT_IMPLEMENTED"),
+ L("ESR_CONNECTION_RESET_BY_PEER"),
+ L("ESR_PROCESS_CREATE_ERROR"),
+ L("ESR_TTS_NO_ENGINE"),
+ L("ESR_MUTEX_CREATION_ERROR"),
+ L("ESR_DEADLOCK"),
+ L("invalid return code") /* must remain last element for ESR_rc2str() to function */
+ };
+
+const LCHAR* ESR_rc2str(const ESR_ReturnCode rc)
+{
+ if (rc >= RETURNCODE_COUNT)
+ return rcStringMapping[RETURNCODE_COUNT];
+ return rcStringMapping[rc];
+}
+
+
+#ifdef _WIN32
+__declspec(thread) unsigned long stackEnd = 0;
+__declspec(thread) unsigned long stackBeginMin = LONG_MAX;
+
+#include "plog.h"
+
+#ifdef __cplusplus
+extern "C"
+#endif
+
+ void __declspec(naked) _cdecl _penter(void)
+{
+ _asm
+ {
+ pushad
+ mov ebp, esp
+ }
+
+ {
+ unsigned long espBuffer;
+
+ _asm
+ {
+ mov espBuffer, esp
+ }
+ if (espBuffer > stackEnd)
+ stackEnd = espBuffer;
+ //printf("\nThread=%d,-addressStack-begin=%lu\n", GetCurrentThreadId(), espBuffer);
+ }
+
+ _asm
+ {
+ popad
+ ret
+ }
+}
+
+void __declspec(naked) _cdecl _pexit(void)
+{
+ _asm
+ {
+ pushad
+ mov ebp, esp
+ }
+
+ {
+ unsigned long stackBegin;
+
+ _asm
+ {
+ sub esp, 4
+ mov stackBegin, esp
+ }
+
+ if (stackBegin < stackBeginMin)
+ {
+ stackBeginMin = stackBegin;
+ if (stackEnd - stackBegin > 20*1000)
+ printf("*****************************\nThread %d, Maximum stack usage=%lu\n*******************************\n", GetCurrentThreadId(), (stackEnd - stackBeginMin));
+ }
+ /*
+ if (stackEnd - stackBegin > 15*1000)
+ printf("\nThread=%d,Stack-size=%lu\n", GetCurrentThreadId(), (stackEnd - stackBegin));
+ */
+
+ _asm
+ {
+ add esp, 4
+ }
+ }
+
+ _asm
+ {
+ popad
+ ret
+ }
+}
+#endif
diff --git a/portable/src/LCHAR.c b/portable/src/LCHAR.c
new file mode 100644
index 0000000..d17e0e8
--- /dev/null
+++ b/portable/src/LCHAR.c
@@ -0,0 +1,355 @@
+/*---------------------------------------------------------------------------*
+ * LCHAR.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "LCHAR.h"
+#include "plog.h"
+#include "pmemory.h"
+
+#define MTAG NULL
+
+ESR_ReturnCode lstrtrim(LCHAR* text)
+{
+ size_t beginning, ending, len;
+
+ len = LSTRLEN(text);
+
+ /* locating first non-whitespace character from beginning */
+ for (beginning = 0; beginning < len && LISSPACE(text[beginning]); ++beginning);
+ /* locating first non-whitespace character from end */
+ for (ending = len - 1; ending > beginning && LISSPACE(text[ending]); --ending);
+
+ if (beginning > 0 && beginning <= ending)
+ LMEMMOVE(text, text + beginning, ending - beginning + 1);
+ text[ending-beginning+1] = '\0';
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode lstrinsert(const LCHAR* source, LCHAR* target, size_t offset, size_t* len)
+{
+ ESR_ReturnCode rc;
+
+ if (source == NULL || target == NULL || len == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ if (LSTRLEN(source) + LSTRLEN(target) + 1 > *len)
+ {
+ *len = LSTRLEN(source) + LSTRLEN(target) + 1;
+ rc = ESR_BUFFER_OVERFLOW;
+ PLOG_DBG_TRACE((ESR_rc2str(rc)));
+ goto CLEANUP;
+ }
+ memmove(target + offset + LSTRLEN(source), target + offset, LSTRLEN(target + offset) + 1);
+ LSTRNCPY(target + offset, source, LSTRLEN(source));
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode lstrreplace(LCHAR* text, const LCHAR source, const LCHAR target)
+{
+ LCHAR* index;
+
+ while (ESR_TRUE)
+ {
+ index = LSTRCHR(text, source);
+ if (index == NULL)
+ break;
+ *index = target;
+ }
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode lstrtoi(const LCHAR* text, int* result, int base)
+{
+ LCHAR* endPtr;
+
+ if (result == NULL)
+ return ESR_INVALID_ARGUMENT;
+ *result = LSTRTOL(text, &endPtr, base);
+ if (endPtr == text || (!LISSPACE(*endPtr) && *endPtr != L('\0')))
+ return ESR_INVALID_ARGUMENT;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode lstrtoui(const LCHAR* text, unsigned int* result, int base)
+{
+ LCHAR* endPtr;
+
+ if (result == NULL)
+ return ESR_INVALID_ARGUMENT;
+ *result = LSTRTOUL(text, &endPtr, base);
+ if (endPtr == text || (!LISSPACE(*endPtr) && *endPtr != L('\0')))
+ return ESR_INVALID_ARGUMENT;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode lstrtof(const LCHAR* text, float* result)
+{
+ LCHAR* endPtr;
+
+ if (result == NULL)
+ return ESR_INVALID_ARGUMENT;
+ *result = (float) LSTRTOD(text, &endPtr);
+ if (endPtr == text || (!LISSPACE(*endPtr) && *endPtr != L('\0')))
+ return ESR_INVALID_ARGUMENT;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode lstrtob(const LCHAR* text, ESR_BOOL* result)
+{
+ ESR_ReturnCode rc = ESR_SUCCESS;
+ int compare;
+ unsigned int temp;
+
+ if (result == NULL)
+ return ESR_INVALID_ARGUMENT;
+ CHKLOG(rc, lstrcasecmp(text, L("true"), &compare));
+ if (compare == 0)
+ {
+ *result = ESR_TRUE;
+ return ESR_SUCCESS;
+ }
+ CHKLOG(rc, lstrcasecmp(text, L("yes"), &compare));
+ if (compare == 0)
+ {
+ *result = ESR_TRUE;
+ return ESR_SUCCESS;
+ }
+ CHKLOG(rc, lstrcasecmp(text, L("false"), &compare));
+ if (compare == 0)
+ {
+ *result = ESR_FALSE;
+ return ESR_SUCCESS;
+ }
+ CHKLOG(rc, lstrcasecmp(text, L("no"), &compare));
+ if (compare == 0)
+ {
+ *result = ESR_FALSE;
+ return ESR_SUCCESS;
+ }
+
+ /* Check for boolean expressed as an integer value */
+ CHK(rc, lstrtoui(text, &temp, 10));
+ *result = (temp != 0);
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode LCHARGetInt( LCHAR* text, int* value, LCHAR** finalPosition)
+{
+ LCHAR *beg, *end;
+ LCHAR temp;
+ ESR_ReturnCode rc;
+
+ /* Skip whitespace */
+ for (beg = text; *beg != L('\0') && LISSPACE(*beg); ++beg);
+ if (beg == NULL)
+ return ESR_INVALID_ARGUMENT; /* invalid command syntax */
+ /* Find next whitespace */
+ for (end = beg; *end != L('\0') && !LISSPACE(*end); ++end);
+ if (end == NULL)
+ return ESR_INVALID_ARGUMENT; /* invalid command syntax */
+
+ temp = *end;
+ *end = L('\0');
+ rc = lstrtoi(beg, value, 10);
+ if (rc != ESR_SUCCESS)
+ {
+ *end = temp;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ *end = temp;
+ if (finalPosition != NULL)
+ *finalPosition = end;
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode lstrlwr(LCHAR* string)
+{
+ if (string)
+ {
+ while (*string)
+ {
+ if (LISALPHA(*string))
+ *string = (LCHAR) LTOLOWER(*string);
+ ++string;
+ }
+ }
+ else
+ return ESR_INVALID_ARGUMENT;
+
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode lstrupr(LCHAR* string)
+{
+ if (string)
+ {
+ while (*string)
+ {
+ if (LISALPHA(*string))
+ *string = (LCHAR) LTOUPPER(*string);
+ ++string;
+ }
+ }
+ else
+ return ESR_INVALID_ARGUMENT;
+
+ return ESR_SUCCESS;
+}
+
+/* strcasecmp is not POSIX.4 API */
+ESR_ReturnCode lstrcasecmp(const LCHAR *string1, const LCHAR *string2, int *result)
+{
+
+ if (!string1 || !string2)
+ return ESR_INVALID_ARGUMENT;
+
+ while (LTOUPPER(*string1) == LTOUPPER(*string2++))
+ {
+ if (!*string1++)
+ {
+ *result = 0;
+ return ESR_SUCCESS;
+ }
+ }
+
+ *result = LTOUPPER(*string1) - LTOUPPER(*--string2);
+ return ESR_SUCCESS;
+}
+
+/**
+ * This code is from MS SDK: C:\PROGRAM FILES\MICROSOFT SDK\src\crt\xtoa.c
+ * Buffer overflow checking is left up to the caller.
+ *
+ * @param value Number to be converted
+ * @param string String result
+ * @param radix Base of value; must be in the range 2 - 36
+ */
+static void pxtoa(unsigned long val, LCHAR *buf, unsigned radix, int is_neg)
+{
+ LCHAR *p; /* pointer to traverse string */
+ LCHAR *firstdig; /* pointer to first digit */
+ LCHAR temp; /* temp char */
+ unsigned digval; /* value of digit */
+
+ p = buf;
+
+ if (is_neg)
+ {
+ /* negative, so output '-' and negate */
+ *p++ = '-';
+ val = (unsigned long)(-(long)val);
+ }
+
+ firstdig = p; /* save pointer to first digit */
+
+ do
+ {
+ digval = (unsigned)(val % radix);
+ val /= radix; /* get next digit */
+
+ /* convert to ascii and store */
+ if (digval > 9)
+ *p++ = (LCHAR)(digval - 10 + 'a'); /* a letter */
+ else
+ *p++ = (LCHAR)(digval + '0'); /* a digit */
+ }
+ while (val > 0);
+
+ /* We now have the digit of the number in the buffer, but in reverse
+ order. Thus we reverse them now. */
+
+ *p-- = '\0'; /* terminate string; p points to last digit */
+
+ do
+ {
+ temp = *p;
+ *p = *firstdig;
+ *firstdig = temp; /* swap *p and *firstdig */
+ --p;
+ ++firstdig; /* advance to next two digits */
+ }
+ while (firstdig < p); /* repeat until halfway */
+}
+
+/*
+ * Convert an integer to a string.
+ */
+ESR_ReturnCode litostr(int value, LCHAR *string, size_t *len, int radix)
+{
+ size_t size;
+ /* pxtoa() is guaranteed not to overflow past 33 characters */
+ LCHAR buffer[33];
+
+ if (!string)
+ return ESR_INVALID_ARGUMENT;
+
+ if (radix == 10 && value < 0)
+ pxtoa((unsigned long) value, buffer, radix, 1);
+ else
+ pxtoa((unsigned long) value, buffer, radix, 0);
+
+ size = LSTRLEN(buffer);
+
+ if (size >= *len) /* + null-terminated character */
+ {
+ *len = size;
+ return ESR_BUFFER_OVERFLOW;
+ }
+ else
+ LSTRCPY(string, buffer);
+
+ return ESR_SUCCESS;
+}
+
+
+/* Convert an unsigned long integer to a string. */
+ESR_ReturnCode lultostr(unsigned long value, LCHAR *string, size_t *len, int radix)
+{
+ size_t size;
+ LCHAR buffer[33];
+
+ if (!string)
+ return ESR_INVALID_ARGUMENT;
+
+ pxtoa(value, buffer, radix, 0);
+
+ size = LSTRLEN(buffer);
+
+ if (size >= *len) /* + null-terminated character */
+ {
+ *len = size;
+ return ESR_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ *len = size;
+ LSTRCPY(string, buffer);
+ }
+
+ return ESR_SUCCESS;
+}
diff --git a/portable/src/PANSIFileImpl.c b/portable/src/PANSIFileImpl.c
new file mode 100644
index 0000000..6d9a261
--- /dev/null
+++ b/portable/src/PANSIFileImpl.c
@@ -0,0 +1,449 @@
+/*---------------------------------------------------------------------------*
+ * PANSIFileImpl.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "errno.h"
+#include "passert.h"
+#include "pendian.h"
+#include "PFileImpl.h"
+#include "PANSIFileImpl.h"
+#include "PFileSystem.h"
+#include "ESR_ReturnCode.h"
+#include "plog.h"
+#include "pmemory.h"
+#include "pstdio.h"
+#include "ptypes.h"
+
+#define MTAG NULL
+
+ESR_ReturnCode PANSIFileCreateImpl(const LCHAR* filename, ESR_BOOL isLittleEndian, PFile** self)
+{
+ PANSIFileImpl* impl = NULL;
+ ESR_ReturnCode rc;
+
+ impl = NEW(PANSIFileImpl, MTAG);
+ if (impl == NULL)
+ {
+ rc = ESR_OUT_OF_MEMORY;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+
+ PFileCreateImpl(&impl->Interface.Interface, filename, isLittleEndian);
+ impl->Interface.Interface.close = &PANSIFileCloseImpl;
+ impl->Interface.Interface.clearError = &PANSIFileClearErrorImpl;
+ impl->Interface.Interface.destroy = &PANSIFileDestroyImpl;
+ impl->Interface.Interface.fgetc = &PANSIFileFgetcImpl;
+ impl->Interface.Interface.fgets = &PANSIFileFgetsImpl;
+ impl->Interface.Interface.getPosition = &PANSIFileGetPositionImpl;
+ impl->Interface.Interface.hideMemoryAllocation = &PANSIFileHideMemoryAllocation;
+ impl->Interface.Interface.isEOF = &PANSIFileIsEOFImpl;
+ impl->Interface.Interface.isErrorSet = &PANSIFileIsErrorSetImpl;
+ impl->Interface.Interface.isOpen = &PANSIFileIsOpenImpl;
+ impl->Interface.Interface.open = &PANSIFileOpenImpl;
+ impl->Interface.Interface.read = &PANSIFileReadImpl;
+ impl->Interface.Interface.seek = &PANSIFileSeekImpl;
+ impl->Interface.Interface.flush = &PANSIFileFlushImpl;
+ impl->Interface.Interface.write = &PANSIFileWriteImpl;
+
+ impl->Interface.filename[0] = 0;
+ impl->value = NULL;
+
+ LSTRCAT(impl->Interface.filename, filename);
+ *self = &impl->Interface.Interface;
+ return ESR_SUCCESS;
+CLEANUP:
+ if (impl != NULL)
+ impl->Interface.Interface.destroy(&impl->Interface.Interface);
+ return rc;
+}
+
+ESR_ReturnCode PANSIFileDestroyImpl(PFile* self)
+{
+ ESR_ReturnCode rc;
+
+ CHK(rc, PFileDestroyImpl(self));
+ FREE(self);
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+
+#ifdef USE_THREAD
+#define LOCK_MUTEX(rc, impl) \
+ if (impl->Interface.lock != NULL) \
+ CHKLOG(rc, PtrdMonitorLock(impl->Interface.lock));
+#else
+#define LOCK_MUTEX(rc, impl)
+#endif
+
+
+#ifdef USE_THREAD
+#define CLEANUP_AND_RETURN(rc, impl) \
+ if (impl->Interface.lock!=NULL) \
+ CHKLOG(rc, PtrdMonitorUnlock(impl->Interface.lock)); \
+ return ESR_SUCCESS; \
+ CLEANUP: \
+ if (impl->Interface.lock!=NULL) \
+ PtrdMonitorUnlock(impl->Interface.lock); \
+ return rc;
+#else
+#define CLEANUP_AND_RETURN(rc, impl) \
+ return ESR_SUCCESS; \
+ CLEANUP: \
+ return rc;
+#endif
+
+
+ESR_ReturnCode PANSIFileOpenImpl(PFile* self, const LCHAR* mode)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ if (impl->value != NULL)
+ {
+ rc = ESR_ALREADY_OPEN;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ impl->value = fopen(impl->Interface.filename, mode);
+
+ if (impl->value == NULL)
+ {
+ LCHAR path[P_PATH_MAX];
+ size_t len;
+
+ len = P_PATH_MAX;
+ CHKLOG(rc, PFileSystemGetcwd(path, &len));
+ rc = ESR_OPEN_ERROR;
+ /* PLOG_DBG_TRACE((L("%s: filename=%s, cwd=%s"), ESR_rc2str(rc), impl->Interface.filename, path)); */
+ PLogError(L("%s: filename=%s, cwd=%s"), ESR_rc2str(rc), impl->Interface.filename, path);
+ goto CLEANUP;
+ }
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileCloseImpl(PFile* self)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ if (fclose(impl->value) != 0)
+ {
+ rc = ESR_CLOSE_ERROR;
+ PLogMessage(L("%s: file %s, handle"), ESR_rc2str(rc), impl->Interface.filename, impl->value);
+ goto CLEANUP;
+ }
+ impl->value = NULL;
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileReadImpl(PFile* self, void* buffer, size_t size, size_t* count)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ if (count == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+
+ if (size != 0 && *count != 0)
+ {
+ ESR_BOOL needToSwap;
+
+ *count = fread(buffer, size, *count, impl->value);
+ if (*count == 0 && ferror(impl->value))
+ {
+ rc = ESR_READ_ERROR;
+ PLogMessage(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+
+#ifdef __LITTLE_ENDIAN
+ needToSwap = !impl->Interface.littleEndian;
+#else
+ needToSwap = impl->Interface.littleEndian;
+#endif
+
+ if (needToSwap)
+ swap_byte_order(buffer, *count, size);
+ }
+ else
+ *count = 0;
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileWriteImpl(PFile* self, void* buffer, size_t size, size_t* count)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+ size_t requested = *count;
+
+ LOCK_MUTEX(rc, impl);
+ if (count == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ if (size != 0 && *count != 0)
+ {
+ ESR_BOOL needToSwap;
+ void* temp;
+
+#ifdef __LITTLE_ENDIAN
+ needToSwap = !impl->Interface.littleEndian;
+#else
+ needToSwap = impl->Interface.littleEndian;
+#endif
+ if (needToSwap)
+ {
+ temp = MALLOC(*count * size, MTAG);
+ if (temp == NULL)
+ {
+ rc = ESR_OUT_OF_MEMORY;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ memcpy(temp, buffer, *count * size);
+
+ swap_byte_order(temp, *count, size);
+ }
+ else
+ temp = buffer;
+
+ *count = fwrite(temp, size, *count, impl->value);
+ if (needToSwap)
+ {
+ FREE(temp);
+ temp = NULL;
+ }
+
+ if (*count < requested)
+ {
+ rc = ESR_WRITE_ERROR;
+ PLogMessage(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ }
+ else
+ *count = 0;
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileFlushImpl(PFile* self)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ if (fflush(impl->value) != 0)
+ {
+ rc = ESR_FLUSH_ERROR;
+ PLogMessage(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileSeekImpl(PFile* self, long offset, int origin)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ if (fseek(impl->value, offset, origin) != 0)
+ {
+ rc = ESR_SEEK_ERROR;
+ PLogMessage(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileGetPositionImpl(PFile* self, size_t* position)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+ long pos;
+
+ LOCK_MUTEX(rc, impl);
+ pos = ftell(impl->value);
+ if (pos == -1)
+ {
+ switch (errno)
+ {
+ case EBADF:
+ rc = ESR_INVALID_STATE;
+ PLogError(L("%s: Got EBADF"), rc);
+ goto CLEANUP;
+ case EINVAL:
+ rc = ESR_INVALID_STATE;
+ PLogError(L("%s: Got EINVAL"), rc);
+ goto CLEANUP;
+ default:
+ rc = ESR_INVALID_STATE;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ }
+ *position = pos;
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileIsOpenImpl(PFile* self, ESR_BOOL* isOpen)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ if (isOpen == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ *isOpen = impl->value != NULL;
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileIsEOFImpl(PFile* self, ESR_BOOL* isEof)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ if (isEof == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+#ifdef NO_FEOF
+ {
+ long posCur; /* remember current file position */
+ long posEnd; /* end of file position */
+
+ posCur = ftell(impl->value);
+ fseek(impl->value, 0, SEEK_END);
+ posEnd = ftell(impl->value);
+ *isEof = (posCur == posEnd);
+ fseek(impl->value, posCur, SEEK_SET); /* restore position in file */
+ }
+#else
+ *isEof = feof(impl->value) != 0;
+#endif
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileIsErrorSetImpl(PFile* self, ESR_BOOL* isError)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ if (isError == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ *isError = ferror(impl->value) != 0;
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileClearErrorImpl(PFile* self)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ clearerr(impl->value);
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileFgetsImpl(PFile* self, LCHAR* string, int n, LCHAR** result)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+ LCHAR* temp;
+
+ LOCK_MUTEX(rc, impl);
+ temp = fgets(string, n, impl->value);
+ if (result != NULL)
+ *result = temp;
+ if (temp == NULL && ferror(impl->value))
+ {
+ rc = ESR_INVALID_STATE;
+ PLogMessage(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileFgetcImpl(PFile* self, LINT* result)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ *result = fgetc(impl->value);
+ if (*result == PEOF && ferror(impl->value))
+ {
+ rc = ESR_INVALID_STATE;
+ PLogMessage(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PANSIFileHideMemoryAllocation(PFile* self)
+{
+ PANSIFileImpl* impl = (PANSIFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ LOCK_MUTEX(rc, impl);
+ rc = PMemLogFree(self);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
+ goto CLEANUP;
+ }
+ rc = PMemLogFree(impl->Interface.filename);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
+ goto CLEANUP;
+ }
+#ifdef USE_THREAD
+ rc = PMemLogFree(impl->Interface.lock);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
+ goto CLEANUP;
+ }
+#endif
+ CLEANUP_AND_RETURN(rc, impl);
+}
diff --git a/portable/src/PANSIFileSystem.c b/portable/src/PANSIFileSystem.c
new file mode 100644
index 0000000..70c7b5d
--- /dev/null
+++ b/portable/src/PANSIFileSystem.c
@@ -0,0 +1,52 @@
+/*---------------------------------------------------------------------------*
+ * PANSIFileSystem.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "LCHAR.h"
+#include "PANSIFileSystemImpl.h"
+#include "plog.h"
+
+extern PFileSystem* PANSIFileSystemSingleton;
+
+ESR_ReturnCode PANSIFileSystemAddPath(const LCHAR* virtualPath, const LCHAR* realPath)
+{
+ return ((PANSIFileSystem*) PANSIFileSystemSingleton)->addPath(PANSIFileSystemSingleton, virtualPath, realPath);
+}
+
+ESR_ReturnCode PANSIFileSystemRemovePath(const LCHAR* virtualPath)
+{
+ return ((PANSIFileSystem*) PANSIFileSystemSingleton)->removePath(PANSIFileSystemSingleton, virtualPath);
+}
+
+ESR_ReturnCode PANSIFileSystemGetcwd(LCHAR* path, size_t* len)
+{
+ return ((PANSIFileSystem*) PANSIFileSystemSingleton)->getcwd(PANSIFileSystemSingleton, path, len);
+}
+
+ESR_ReturnCode PANSIFileSystemDestroy(void)
+{
+ ESR_ReturnCode rc;
+
+ if (PANSIFileSystemSingleton == NULL)
+ return ESR_SUCCESS;
+ CHKLOG(rc, PANSIFileSystemSingleton->destroy(PANSIFileSystemSingleton));
+ PANSIFileSystemSingleton = NULL;
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
diff --git a/portable/src/PANSIFileSystemImpl.c b/portable/src/PANSIFileSystemImpl.c
new file mode 100644
index 0000000..cbe74b3
--- /dev/null
+++ b/portable/src/PANSIFileSystemImpl.c
@@ -0,0 +1,365 @@
+/*---------------------------------------------------------------------------*
+ * PANSIFileSystemImpl.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+#include "LCHAR.h"
+#include "PFileSystemImpl.h"
+#include "PANSIFileSystemImpl.h"
+#include "PANSIFileImpl.h"
+#include "plog.h"
+#include "pmemory.h"
+
+//extern PFileSystem* PANSIFileSystemSingleton;
+PFileSystem* PANSIFileSystemSingleton = (PFileSystem*)NULL;
+
+#define MTAG NULL
+
+
+#ifdef USE_THREAD
+/* Prototype of private function */
+PORTABLE_API ESR_ReturnCode PtrdFlush();
+#endif
+
+/**
+ * [file path, PFileSystem*] mapping.
+ */
+extern PHashTable* PFileSystemPathMap;
+
+
+ESR_ReturnCode PANSIFileSystemCreate(void)
+{
+ PANSIFileSystemImpl* impl;
+ ESR_ReturnCode rc;
+
+ if (PANSIFileSystemSingleton != NULL)
+ return ESR_SUCCESS;
+ impl = NEW(PANSIFileSystemImpl, MTAG);
+ if (impl == NULL)
+ return ESR_OUT_OF_MEMORY;
+ impl->super.super.destroy = &PANSIFileSystemDestroyImpl;
+ impl->super.super.createPFile = &PANSIFileSystemCreatePFileImpl;
+ impl->super.addPath = &PANSIFileSystemAddPathImpl;
+ impl->super.removePath = &PANSIFileSystemRemovePathImpl;
+ impl->super.getcwd = &PANSIFileSystemGetcwdImpl;
+ impl->super.super.mkdir = &PANSIFileSystemMkdirImpl;
+ impl->super.super.chdir = &PANSIFileSystemChdirImpl;
+
+ CHKLOG(rc, PHashTableCreate(NULL, MTAG, &impl->directoryMap));
+ PANSIFileSystemSingleton = &impl->super.super;
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PANSIFileSystemDestroyImpl(PFileSystem* self)
+{
+ PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self;
+ PHashTableEntry* entry;
+ PHashTableEntry* oldEntry;
+ LCHAR* key;
+ LCHAR* value;
+ ESR_ReturnCode rc;
+
+ if (impl->directoryMap != NULL)
+ {
+ CHKLOG(rc, PHashTableEntryGetFirst(impl->directoryMap, &entry));
+ while (entry != NULL)
+ {
+ CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
+ oldEntry = entry;
+ CHKLOG(rc, PHashTableEntryAdvance(&entry));
+ CHKLOG(rc, PHashTableEntryRemove(oldEntry));
+ CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL));
+ FREE(key);
+ FREE(value);
+ }
+ CHKLOG(rc, PHashTableDestroy(impl->directoryMap));
+ impl->directoryMap = NULL;
+ }
+ FREE(self);
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PANSIFileSystemAddPathImpl(PFileSystem* self, const LCHAR* virtualPath, const LCHAR* realPath)
+{
+ PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self;
+ ESR_BOOL exists;
+ LCHAR* key = NULL;
+ LCHAR* value = NULL;
+ ESR_ReturnCode rc;
+ size_t len;
+
+ if (virtualPath == NULL || realPath == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+
+ len = LSTRLEN(virtualPath) + 1;
+ if (virtualPath[LSTRLEN(virtualPath)-1] != L('/'))
+ ++len;
+ key = MALLOC(sizeof(LCHAR) * len, MTAG);
+ if (key == NULL)
+ {
+ rc = ESR_OUT_OF_MEMORY;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(key, virtualPath);
+ /* Make sure paths end with '/' */
+ CHKLOG(rc, PFileSystemCanonicalSlashes(key));
+ if (key[LSTRLEN(key)-1] != L('/'))
+ LSTRCAT(key, L("/"));
+ value = MALLOC(sizeof(LCHAR) * (LSTRLEN(realPath) + 1), MTAG);
+ if (value == NULL)
+ {
+ rc = ESR_OUT_OF_MEMORY;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(value, realPath);
+
+ /* Make sure realPath is not an empty string */
+ lstrtrim(value);
+ if (LSTRLEN(value) == 0)
+ {
+ FREE(value);
+ value = NULL;
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(L("%s: realPath cannot be empty"), ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+
+ /* Make sure paths end with '/' */
+ CHKLOG(rc, PFileSystemCanonicalSlashes(value));
+ if (value[LSTRLEN(value)-1] != L('/'))
+ LSTRCAT(value, L("/"));
+
+ CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, key, &exists));
+ if (exists)
+ {
+ LCHAR* oldValue;
+
+ CHKLOG(rc, PHashTableGetValue(impl->directoryMap, key, (void **)&oldValue));
+ if (LSTRCMP(oldValue, value) != 0)
+ {
+ rc = ESR_IDENTIFIER_COLLISION;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ }
+ CHKLOG(rc, PHashTablePutValue(impl->directoryMap, key, value, NULL));
+ CHKLOG(rc, PHashTablePutValue(PFileSystemPathMap, key, self, NULL));
+ return ESR_SUCCESS;
+CLEANUP:
+ FREE(key);
+ FREE(value);
+ return rc;
+}
+
+ESR_ReturnCode PANSIFileSystemRemovePathImpl(PFileSystem* self, const LCHAR* virtualPath)
+{
+ PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self;
+ LCHAR path[P_PATH_MAX];
+ LCHAR* key;
+ LCHAR* value;
+ PHashTableEntry* entry;
+ ESR_ReturnCode rc;
+
+ if (virtualPath == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ /* Make sure paths end with '/' */
+ LSTRCPY(path, virtualPath);
+ CHKLOG(rc, PFileSystemCanonicalSlashes(path));
+ if (path[LSTRLEN(path)-1] != L('/'))
+ LSTRCAT(path, L("/"));
+ CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, path, &entry));
+ CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
+ CHKLOG(rc, PHashTableEntryRemove(entry));
+ CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL));
+ FREE(key);
+ FREE(value);
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PANSIFileSystemGetRealPathImpl(PFileSystem* self, LCHAR* path, size_t* len)
+{
+ PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self;
+ PHashTableEntry* entry;
+ LCHAR* key;
+ LCHAR* value;
+ LCHAR* bestKey = NULL;
+ LCHAR* bestValue = NULL;
+ ESR_BOOL isAbsolute;
+ ESR_ReturnCode rc;
+
+ CHKLOG(rc, PFileSystemGetAbsolutePath(path, len));
+ CHKLOG(rc, PHashTableEntryGetFirst(impl->directoryMap, &entry));
+ while (entry != NULL)
+ {
+ CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void**)&key, (void**)&value));
+ if (LSTRNCMP(path, key, LSTRLEN(key)) == 0)
+ {
+ /* File-system handles file path */
+ if (bestKey == NULL || LSTRLEN(key) > LSTRLEN(bestKey))
+ {
+ /* Found a better match -- the new key is a subdirectory of the previous bestKey */
+ bestKey = key;
+ bestValue = value;
+ }
+ }
+ CHKLOG(rc, PHashTableEntryAdvance(&entry));
+ }
+ if (bestKey == NULL)
+ {
+ rc = ESR_INVALID_STATE;
+ PLogError(L("PANSIFileSystem does not handle the specified path: %s"), path);
+ goto CLEANUP;
+ }
+
+ if (LSTRLEN(bestValue) + 1 > *len)
+ {
+ *len = LSTRLEN(bestValue) + 1;
+ rc = ESR_BUFFER_OVERFLOW;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ /* Delete the virtual-path */
+ LSTRCPY(path, path + LSTRLEN(bestKey));
+
+ CHKLOG(rc, PFileSystemIsAbsolutePath(path, &isAbsolute));
+ if (LSTRCMP(bestValue, L("/")) == 0 && isAbsolute)
+ {
+ /* do nothing */
+ }
+ else
+ {
+ /* Insert the key-path */
+ CHKLOG(rc, lstrinsert(bestValue, path, 0, len));
+ }
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PANSIFileSystemCreatePFileImpl(PFileSystem* self, const LCHAR* path, ESR_BOOL littleEndian, PFile** file)
+{
+ LCHAR realPath[P_PATH_MAX];
+ size_t len;
+ ESR_ReturnCode rc;
+
+ LSTRCPY(realPath, path);
+ len = P_PATH_MAX;
+ CHKLOG(rc, PANSIFileSystemGetRealPathImpl(self, realPath, &len));
+ return PANSIFileCreateImpl(realPath, littleEndian, file);
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PANSIFileSystemSetDefault(ESR_BOOL isDefault)
+{
+ PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) PANSIFileSystemSingleton;
+ ESR_BOOL exists;
+ LCHAR* key = NULL;
+ LCHAR* value = NULL;
+ PHashTableEntry* entry;
+ ESR_ReturnCode rc;
+
+ if (isDefault)
+ {
+
+ key = MALLOC(sizeof(LCHAR), MTAG);
+ if (key == NULL)
+ {
+ rc = ESR_OUT_OF_MEMORY;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(key, L(""));
+ value = MALLOC(sizeof(LCHAR), MTAG);
+ if (value == NULL)
+ {
+ rc = ESR_OUT_OF_MEMORY;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(value, L(""));
+
+ CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, key, &exists));
+ if (exists)
+ {
+ LCHAR* key;
+ LCHAR* value;
+
+ CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, L(""), &entry));
+ CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
+ CHKLOG(rc, PHashTableEntryRemove(entry));
+ CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL));
+ FREE(key);
+ FREE(value);
+ }
+ CHKLOG(rc, PHashTablePutValue(impl->directoryMap, key, value, NULL));
+ CHKLOG(rc, PHashTablePutValue(PFileSystemPathMap, key, PANSIFileSystemSingleton, NULL));
+
+ /* Set virtual current working directory to native current working directory */
+ }
+ else
+ {
+ CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, L(""), &exists));
+ if (exists)
+ {
+ LCHAR* key;
+ LCHAR* value;
+
+ CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, L(""), &entry));
+ CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
+
+ CHKLOG(rc, PHashTableContainsKey(PFileSystemPathMap, L(""), &exists));
+ if (exists)
+ {
+ LCHAR* key;
+ PFileSystem* value;
+ PHashTableEntry* entry;
+
+ CHKLOG(rc, PHashTableGetEntry(PFileSystemPathMap, L(""), &entry));
+ CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
+ if (value == PANSIFileSystemSingleton)
+ CHKLOG(rc, PHashTableEntryRemove(entry));
+ }
+
+ CHKLOG(rc, PHashTableEntryRemove(entry));
+ FREE(key);
+ FREE(value);
+ }
+ }
+ return ESR_SUCCESS;
+CLEANUP:
+ FREE(key);
+ FREE(value);
+ return rc;
+}
diff --git a/portable/src/PFile.c b/portable/src/PFile.c
new file mode 100644
index 0000000..06e1317
--- /dev/null
+++ b/portable/src/PFile.c
@@ -0,0 +1,521 @@
+/*---------------------------------------------------------------------------*
+ * PFile.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "LCHAR.h"
+#include "pendian.h"
+#include "PFile.h"
+#include "PFileSystem.h"
+#include "plog.h"
+#include "pstdio.h"
+
+
+ESR_ReturnCode PFileDestroy(PFile* self)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->destroy(self);
+}
+
+ESR_ReturnCode PFileOpen(PFile* self, const LCHAR* mode)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->open(self, mode);
+}
+
+ESR_ReturnCode PFileClose(PFile* self)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->close(self);
+}
+
+ESR_ReturnCode PFileRead(PFile* self, void* buffer, size_t size, size_t* count)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->read(self, buffer, size, count);
+}
+
+ESR_ReturnCode PFileWrite(PFile* self, void* buffer, size_t size, size_t* count)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->write(self, buffer, size, count);
+}
+
+ESR_ReturnCode PFileFlush(PFile* self)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->flush(self);
+}
+
+ESR_ReturnCode PFileSeek(PFile* self, long offset, int origin)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->seek(self, offset, origin);
+}
+
+
+ESR_ReturnCode PFileGetPosition(PFile* self, size_t* position)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->getPosition(self, position);
+}
+
+ESR_ReturnCode PFileIsOpen(PFile* self, ESR_BOOL* isOpen)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->isOpen(self, isOpen);
+}
+
+ESR_ReturnCode PFileIsEOF(PFile* self, ESR_BOOL* isEof)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->isEOF(self, isEof);
+}
+
+ESR_ReturnCode PFileGetFilename(PFile* self, LCHAR* filename, size_t* len)
+{
+ ESR_ReturnCode rc;
+
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ rc = self->getFilename(self, filename, len);
+ return rc;
+}
+
+ESR_ReturnCode PFileIsErrorSet(PFile* self, ESR_BOOL* isError)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->isErrorSet(self, isError);
+}
+
+ESR_ReturnCode PFileClearError(PFile* self)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->clearError(self);
+}
+
+ESR_ReturnCode PFileVfprintf(PFile* self, int* result, const LCHAR* format, va_list args)
+{
+ ESR_ReturnCode rc;
+
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ rc = self->vfprintf(self, result, format, args);
+ return rc;
+}
+
+ESR_ReturnCode PFileFgetc(PFile* self, LINT* result)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->fgetc(self, result);
+}
+
+ESR_ReturnCode PFileFgets(PFile* self, LCHAR* string, int n, LCHAR** result)
+{
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ return self->fgets(self, string, n, result);
+}
+
+ESR_ReturnCode PFileReadInt(PFile* self, int* value)
+{
+ LCHAR number[MAX_INT_DIGITS+1];
+ size_t i, bufferSize, count, totalRead = 0;
+ ESR_ReturnCode rc;
+
+ /* Skip whitespace before token */
+ do
+ {
+ count = pfread(number, sizeof(LCHAR), MAX_INT_DIGITS, self);
+ totalRead += count;
+ if (count < MAX_INT_DIGITS)
+ {
+ if (pferror(self))
+ {
+ rc = ESR_READ_ERROR;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ else
+ {
+ rc = ESR_INVALID_STATE;
+ PLogError(L("%s: reached end of file before finding token"), ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ }
+ /* locate first non-whitespace character */
+ for (i = 0; i < count && LISSPACE(number[i]); ++i);
+ }
+ while (i == count);
+ bufferSize = count - i;
+
+ /* Fill remainder of buffer */
+ if (bufferSize < MAX_INT_DIGITS)
+ {
+ count = pfread(number + bufferSize, sizeof(LCHAR), MAX_INT_DIGITS - bufferSize, self);
+ bufferSize += count;
+ totalRead += count;
+ if (count < MAX_INT_DIGITS - bufferSize && pferror(self))
+ {
+ rc = ESR_READ_ERROR;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ }
+
+ /* locate first whitespace character */
+ for (i = 0; i < bufferSize && !LISSPACE(number[i]); ++i);
+ if (i < bufferSize)
+ {
+ /* unread anything after the token */
+ if (PFileSeek(self, - (int)(bufferSize - i), SEEK_CUR))
+ {
+ rc = ESR_SEEK_ERROR;
+ PLogError(ESR_rc2str(rc));
+ }
+ totalRead -= bufferSize - i;
+ number[i] = L('\0');
+ }
+
+ if (number[0] != L('-') && !LISDIGIT(number[0]))
+ {
+ rc = ESR_INVALID_STATE;
+ PLogError(L("%s: token was not number (%s)"), ESR_rc2str(rc), number);
+ goto CLEANUP;
+ }
+
+ CHKLOG(rc, lstrtoi(number, value, 10));
+ return rc;
+CLEANUP:
+ if (PFileSeek(self, - (int) count, SEEK_CUR))
+ PLogError(L("ESR_SEEK_ERROR"));
+ return rc;
+}
+
+ESR_ReturnCode PFileReadLCHAR(PFile* self, LCHAR* value, size_t len)
+{
+ size_t i, bufferSize, count, totalRead = 0;
+ ESR_ReturnCode rc = ESR_SUCCESS;
+
+ /* Skip whitespace before token */
+ do
+ {
+ count = pfread(value, sizeof(LCHAR), len, self);
+ totalRead += count;
+ if (count < len)
+ {
+ if (pferror(self))
+ {
+ rc = ESR_READ_ERROR;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ else
+ {
+ rc = ESR_INVALID_STATE;
+ PLogError(L("%s: reached end of file before finding token"), ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ }
+ /* locate first non-whitespace character */
+ for (i = 0; i < count && LISSPACE(value[i]); ++i);
+ }
+ while (i == count);
+ bufferSize = count - i;
+
+ /* Fill remainder of buffer */
+ if (bufferSize < len)
+ {
+ count = pfread(value + bufferSize, sizeof(LCHAR), len - bufferSize, self);
+ bufferSize += count;
+ totalRead += count;
+ if (count < len - bufferSize && pferror(self))
+ {
+ rc = ESR_READ_ERROR;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ }
+
+ /* locate first whitespace character */
+ for (i = 0; i < bufferSize && !LISSPACE(value[i]); ++i);
+ if (i < bufferSize)
+ {
+ /* unread anything after the token */
+ if (PFileSeek(self, -(int)(bufferSize - i), SEEK_CUR))
+ {
+ rc = ESR_SEEK_ERROR;
+ PLogError(ESR_rc2str(rc));
+ }
+ totalRead -= bufferSize - i;
+ value[i] = L('\0');
+ }
+ return rc;
+CLEANUP:
+ if (PFileSeek(self, - (int) count, SEEK_CUR))
+ PLogError(L("ESR_SEEK_ERROR"));
+ return rc;
+}
+
+PFile* pfopen(const LCHAR* filename, const LCHAR* mode)
+{
+ PFile* result;
+ ESR_ReturnCode rc;
+ ESR_BOOL isLittleEndian;
+
+#if __BYTE_ORDER==__LITTLE_ENDIAN
+ isLittleEndian = ESR_TRUE;
+#else
+ isLittleEndian = ESR_FALSE;
+#endif
+
+ rc = PFileSystemCreatePFile(filename, isLittleEndian, &result);
+ if (rc != ESR_SUCCESS)
+ return NULL;
+ rc = result->open(result, mode);
+ if (rc != ESR_SUCCESS)
+ {
+ result->destroy(result);
+ return NULL;
+ }
+ return result;
+}
+
+size_t pfread(void* buffer, size_t size, size_t count, PFile* stream)
+{
+ ESR_ReturnCode rc;
+
+ rc = PFileRead(stream, buffer, size, &count);
+ if (rc != ESR_SUCCESS)
+ return 0;
+ return count;
+}
+
+size_t pfwrite(void* buffer, size_t size, size_t count, PFile* stream)
+{
+ ESR_ReturnCode rc;
+
+ rc = PFileWrite(stream, buffer, size, &count);
+ if (rc != ESR_SUCCESS)
+ return 0;
+ return count;
+}
+
+int pfclose(PFile* stream)
+{
+ ESR_ReturnCode rc;
+
+ rc = PFileDestroy(stream);
+ if (rc != ESR_SUCCESS)
+ return PEOF;
+ return 0;
+}
+
+void prewind(PFile* stream)
+{
+ PFileSeek(stream, 0, SEEK_SET);
+}
+
+int pfseek(PFile* stream, long offset, int origin)
+{
+ ESR_ReturnCode rc;
+
+ rc = PFileSeek(stream, offset, origin);
+ if (rc != ESR_SUCCESS)
+ return 1;
+ return 0;
+}
+
+long pftell(PFile* stream)
+{
+ size_t result;
+ ESR_ReturnCode rc;
+
+ rc = PFileGetPosition(stream, &result);
+ if (rc != ESR_SUCCESS)
+ return -1;
+ return result;
+}
+
+int pfeof(PFile* stream)
+{
+ ESR_BOOL eof;
+
+ PFileIsEOF(stream, &eof);
+ if (!eof)
+ return 0;
+ return 1;
+}
+
+int pferror(PFile* stream)
+{
+ ESR_BOOL error;
+
+ PFileIsErrorSet(stream, &error);
+ if (!error)
+ return 0;
+ return 1;
+}
+
+void pclearerr(PFile* stream)
+{
+ PFileClearError(stream);
+}
+
+int pfflush(PFile* stream)
+{
+ ESR_ReturnCode rc;
+
+ rc = PFileFlush(stream);
+ if (rc != ESR_SUCCESS)
+ return PEOF;
+ return 0;
+}
+
+LCHAR* pfgets(LCHAR* string, int n, PFile* self)
+{
+ LCHAR* result;
+ ESR_ReturnCode rc;
+
+ rc = PFileFgets(self, string, n, &result);
+ if (rc != ESR_SUCCESS)
+ return NULL;
+ return result;
+}
+
+LINT pfgetc(PFile* self)
+{
+ LINT result;
+ ESR_ReturnCode rc;
+
+ rc = PFileFgetc(self, &result);
+ if (rc != ESR_SUCCESS)
+ return PEOF;
+ return result;
+}
+
+int pfprintf(PFile* stream, const LCHAR* format, ...)
+{
+#ifdef FINAL_RELEASE
+ return 0;
+#else
+ va_list args;
+ int result;
+ ESR_ReturnCode rc;
+
+ va_start(args, format);
+ rc = PFileVfprintf(stream, &result, format, args);
+ va_end(args);
+ if (rc != ESR_SUCCESS)
+ return -1;
+ return result;
+#endif
+}
+
+int pvfprintf(PFile* stream, const LCHAR* format, va_list argptr)
+{
+#ifdef FINAL_RELEASE
+ return 0;
+#else
+ int result;
+ ESR_ReturnCode rc;
+
+ rc = PFileVfprintf(stream, &result, format, argptr);
+ if (rc != ESR_SUCCESS)
+ return -1;
+ return result;
+#endif
+}
+
+int pprintf(const LCHAR* format, ...)
+{
+#ifdef FINAL_RELEASE
+ return 0;
+#else
+ va_list args;
+ int result;
+ ESR_ReturnCode rc;
+
+ va_start(args, format);
+ rc = PFileVfprintf(PSTDOUT, &result, format, args);
+ va_end(args);
+ if (rc != ESR_SUCCESS)
+ return -1;
+ return result;
+#endif
+}
diff --git a/portable/src/PFileImpl.c b/portable/src/PFileImpl.c
new file mode 100644
index 0000000..72abfba
--- /dev/null
+++ b/portable/src/PFileImpl.c
@@ -0,0 +1,199 @@
+/*---------------------------------------------------------------------------*
+ * PFileImpl.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "passert.h"
+#include "pendian.h"
+#include "PFileImpl.h"
+#include "PFileSystem.h"
+#include "plog.h"
+#include "pmemory.h"
+#include "pstdio.h"
+#include "ptypes.h"
+
+#define MTAG NULL
+
+
+/**
+ * Initializes variables declared in the superinterface.
+ */
+ESR_ReturnCode PFileCreateImpl(PFile* self, const LCHAR* filename, ESR_BOOL isLittleEndian)
+{
+ PFileImpl* impl = (PFileImpl*) self;
+ ESR_ReturnCode rc;
+#ifdef USE_THREAD
+ ESR_BOOL threadingEnabled;
+#endif
+
+#ifdef USE_THREAD
+ impl->lock = NULL;
+#endif
+ impl->littleEndian = isLittleEndian;
+
+ impl->Interface.destroy = &PFileDestroyImpl;
+ impl->Interface.getFilename = &PFileGetFilenameImpl;
+ impl->Interface.vfprintf = &PFileVfprintfImpl;
+ impl->filename = MALLOC(sizeof(LCHAR) * (LSTRLEN(filename) + 1), MTAG);
+
+ if (impl->filename == NULL)
+ {
+ rc = ESR_OUT_OF_MEMORY;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(impl->filename, filename);
+
+#ifdef USE_THREAD
+ rc = PtrdIsEnabled(&threadingEnabled);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, L("[%s:%d] PtrdIsEnabled failed with %s\n"), __FILE__, __LINE__, ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ if (threadingEnabled)
+ {
+ rc = PtrdMonitorCreate(&impl->lock);
+ if (rc != ESR_SUCCESS)
+ goto CLEANUP;
+ }
+#endif
+ return ESR_SUCCESS;
+CLEANUP:
+ self->destroy(self);
+ return rc;
+}
+
+
+#ifdef USE_THREAD
+#define LOCK_MUTEX(rc, impl) \
+ if (impl->lock != NULL) \
+ CHKLOG(rc, PtrdMonitorLock(impl->lock));
+#else
+#define LOCK_MUTEX(rc, impl)
+#endif
+
+
+#ifdef USE_THREAD
+#define CLEANUP_AND_RETURN(rc, impl) \
+ if (impl->lock!=NULL) \
+ CHKLOG(rc, PtrdMonitorUnlock(impl->lock)); \
+ return ESR_SUCCESS; \
+ CLEANUP: \
+ if (impl->lock!=NULL) \
+ PtrdMonitorUnlock(impl->lock); \
+ return rc;
+#else
+#define CLEANUP_AND_RETURN(rc, impl) \
+ return ESR_SUCCESS; \
+ CLEANUP: \
+ return rc;
+#endif
+
+
+ESR_ReturnCode PFileDestroyImpl(PFile* self)
+{
+ PFileImpl* impl = (PFileImpl*) self;
+ ESR_ReturnCode rc;
+ ESR_BOOL isOpen;
+
+ LOCK_MUTEX(rc, impl);
+ CHKLOG(rc, self->isOpen(self, &isOpen));
+ if (isOpen)
+ CHKLOG(rc, self->close(self));
+ if (impl->filename)
+ {
+ FREE(impl->filename);
+ impl->filename = NULL;
+ }
+#ifdef USE_THREAD
+ if (impl->lock != NULL)
+ {
+ PtrdMonitorUnlock(impl->lock);
+ rc = PtrdMonitorDestroy(impl->lock);
+ if (rc != ESR_SUCCESS)
+ goto CLEANUP;
+ }
+#endif
+ return ESR_SUCCESS;
+CLEANUP:
+#ifdef USE_THREAD
+ if (impl->lock != NULL)
+ PtrdMonitorUnlock(impl->lock);
+#endif
+ return rc;
+}
+
+ESR_ReturnCode PFileGetFilenameImpl(PFile* self, LCHAR* filename, size_t* len)
+{
+ PFileImpl* impl = (PFileImpl*) self;
+ ESR_ReturnCode rc;
+
+ if (self == NULL || len == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+ LOCK_MUTEX(rc, impl);
+ if (LSTRLEN(impl->filename) + 1 > *len)
+ {
+ *len = LSTRLEN(impl->filename) + 1;
+ rc = ESR_BUFFER_OVERFLOW;
+ goto CLEANUP;
+ }
+ LSTRCPY(filename, impl->filename);
+ CLEANUP_AND_RETURN(rc, impl);
+}
+
+ESR_ReturnCode PFileVfprintfImpl(PFile* self, int* result, const LCHAR* format, va_list args)
+{
+ ESR_ReturnCode rc;
+ ESR_BOOL isOpen;
+#define BUFFER_SIZE 5120
+ static LCHAR buffer[BUFFER_SIZE];
+ size_t len;
+
+ if (self == NULL)
+ {
+ PLogError(L("ESR_INVALID_ARGUMENT"));
+ return ESR_INVALID_ARGUMENT;
+ }
+
+ CHKLOG(rc, self->isOpen(self, &isOpen));
+ if (!isOpen)
+ {
+ rc = ESR_OPEN_ERROR;
+ PLogError(L("%s: cannot operate on closed file"), ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+
+ /*
+ * fprintf() is computationally expensive, so we compute its output without grabbing a lock
+ * and only lock while actually writing the results into the file.
+ */
+ if (result != NULL)
+ *result = vsprintf(buffer, format, args);
+ else
+ vsprintf(buffer, format, args);
+ len = LSTRLEN(buffer);
+ passert(len < BUFFER_SIZE);
+
+ CHKLOG(rc, self->write(self, buffer, sizeof(LCHAR), &len));
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
diff --git a/portable/src/PFileSystem.c b/portable/src/PFileSystem.c
new file mode 100644
index 0000000..14fbf6b
--- /dev/null
+++ b/portable/src/PFileSystem.c
@@ -0,0 +1,552 @@
+/*---------------------------------------------------------------------------*
+ * PFileSystem.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "ArrayList.h"
+#include "LCHAR.h"
+#include "PFileSystem.h"
+#include "PFileSystemImpl.h"
+#include "phashtable.h"
+#include "plog.h"
+#include "pmemory.h"
+
+
+#define MTAG NULL
+
+/**
+ * Indicates if PFileSystem is initialized.
+ */
+extern ESR_BOOL PFileSystemCreated;
+
+/**
+ * [file path, PFileSystem*] mapping.
+ */
+extern PHashTable* PFileSystemPathMap;
+
+/**
+ * Current working directory.
+ */
+extern LCHAR PFileSystemCurrentDirectory[P_PATH_MAX];
+
+PORTABLE_API ESR_ReturnCode PFileSystemCanonicalSlashes(LCHAR* path)
+{
+ ESR_ReturnCode rc;
+
+ if (path == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+
+ lstrtrim(path);
+ CHKLOG(rc, lstrreplace(path, L('\\'), L('/')));
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemLinearToPathTokens(const LCHAR* path, LCHAR*** tokenArray, size_t* count)
+{
+ ESR_ReturnCode rc;
+ const LCHAR* beginning;
+ const LCHAR* ending;
+ LCHAR linear[P_PATH_MAX];
+ ArrayList* arrayList = NULL;
+ LCHAR* value = NULL;
+ size_t i;
+
+ if (path == NULL || tokenArray == NULL || count == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(linear, path);
+ CHKLOG(rc, PFileSystemCanonicalSlashes(linear));
+ CHKLOG(rc, ArrayListCreate(&arrayList));
+ beginning = linear;
+ while (ESR_TRUE)
+ {
+ ending = LSTRCHR(beginning, L('/'));
+ if (ending == NULL)
+ ending = beginning + LSTRLEN(beginning);
+ value = MALLOC(sizeof(LCHAR) * (ending - beginning + 1 + 1), MTAG);
+ if (value == NULL)
+ {
+ rc = ESR_OUT_OF_MEMORY;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRNCPY(value, beginning, ending - beginning + 1);
+ value[ending-beginning+1] = L('\0');
+ CHKLOG(rc, lstrtrim(value));
+ if (LSTRLEN(value) == 0)
+ {
+ FREE(value);
+ value = NULL;
+ }
+ else
+ {
+ CHKLOG(rc, arrayList->add(arrayList, value));
+ value = NULL;
+ }
+ if (*ending == 0)
+ break;
+ beginning = ending + 1;
+ }
+
+ /* Build static token array */
+ CHKLOG(rc, arrayList->getSize(arrayList, count));
+ *tokenArray = MALLOC(*count * sizeof(LCHAR*), MTAG);
+ if (*tokenArray == NULL)
+ {
+ rc = ESR_OUT_OF_MEMORY;
+ goto CLEANUP;
+ }
+ for (i = 0; i < *count; ++i)
+ {
+ rc = arrayList->get(arrayList, i, (void**)(&(*tokenArray)[i]));
+ if (rc != ESR_SUCCESS)
+ goto CLEANUP;
+ }
+ rc = arrayList->destroy(arrayList);
+ if (rc != ESR_SUCCESS)
+ goto CLEANUP;
+ return ESR_SUCCESS;
+CLEANUP:
+ FREE(value);
+ if (arrayList != NULL)
+ {
+ ESR_ReturnCode cleanRC;
+
+ cleanRC = arrayList->getSize(arrayList, count);
+ if (cleanRC != ESR_SUCCESS)
+ return rc;
+ for (i = 0; i < *count; ++i)
+ {
+ cleanRC = arrayList->get(arrayList, 0, (void**)&value);
+ if (cleanRC != ESR_SUCCESS)
+ return rc;
+ FREE(value);
+ cleanRC = arrayList->remove(arrayList, 0);
+ if (cleanRC != ESR_SUCCESS)
+ return rc;
+ }
+ arrayList->destroy(arrayList);
+ }
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemIsAbsolutePath(const LCHAR* path, ESR_BOOL* isAbsolute)
+{
+ LCHAR canonical[P_PATH_MAX];
+ ESR_ReturnCode rc;
+
+ if (isAbsolute == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(canonical, path);
+ CHKLOG(rc, PFileSystemCanonicalSlashes(canonical));
+
+ *isAbsolute = (canonical[0] == '/' ||
+ (LISALPHA(canonical[0]) && canonical[1] == ':' && canonical[2] == '/'));
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemGetAbsolutePath(LCHAR* path, size_t* len)
+{
+ ESR_ReturnCode rc;
+#define MAX_PATH_TOKENS 20
+ LCHAR** tokens = NULL;
+ size_t tokenLen = 0, i;
+ ESR_BOOL isAbsolute;
+
+ if (path == NULL || len == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ CHKLOG(rc, PFileSystemIsAbsolutePath(path, &isAbsolute));
+
+ /* Prefix relative paths with the current working directory */
+ if (!isAbsolute)
+ {
+ LCHAR cwd[P_PATH_MAX];
+ size_t len2;
+
+ len2 = P_PATH_MAX;
+ CHKLOG(rc, PFileSystemGetcwd(cwd, &len2));
+ len2 = *len;
+ CHKLOG(rc, lstrinsert(cwd, path, 0, &len2));
+ }
+
+ CHKLOG(rc, PFileSystemCanonicalSlashes(path));
+ tokenLen = MAX_PATH_TOKENS;
+ CHKLOG(rc, PFileSystemLinearToPathTokens(path, &tokens, &tokenLen));
+
+ LSTRCPY(path, L(""));
+ for (i = 0; i < tokenLen; ++i)
+ {
+ if (LSTRCMP(tokens[i], L("../")) == 0)
+ {
+ size_t len2;
+
+ len2 = *len;
+ passert(path[LSTRLEN(path)-1] == L('/'));
+ CHKLOG(rc, PFileSystemGetParentDirectory(path, &len2));
+ }
+ else if (LSTRCMP(tokens[i], L("./")) == 0)
+ {
+ if (i > 0)
+ {
+ /* do nothing */
+ }
+ else
+ {
+ LSTRCPY(path, L("./"));
+ }
+ }
+ else
+ LSTRCAT(path, tokens[i]);
+ FREE(tokens[i]);
+ tokens[i] = NULL;
+ }
+ FREE(tokens);
+ return ESR_SUCCESS;
+CLEANUP:
+ if (tokens != NULL)
+ {
+ for (i = 0; i < tokenLen; ++i)
+ {
+ FREE(tokens[i]);
+ tokens[i] = NULL;
+ }
+ }
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemIsCreated(ESR_BOOL* isCreated)
+{
+ ESR_ReturnCode rc;
+
+ if (isCreated == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ *isCreated = PFileSystemCreated;
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+/**
+ * Given a path, returns the associated file-system and relative path.
+ *
+ * @param path Path to look up
+ * @param fs [out] File-system which matches the path
+ * @param relativePath [out] Relative path associated with match (should have length P_PATH_MAX)
+ */
+ESR_ReturnCode PFileSystemGetFS(const LCHAR* path, PFileSystem** fileSystem, LCHAR* relativePath)
+{
+ ESR_ReturnCode rc;
+ PHashTableEntry* entry;
+ LCHAR* key;
+ PFileSystem* value;
+ LCHAR* bestKey = NULL;
+ PFileSystem* bestValue = NULL;
+
+ CHKLOG(rc, PHashTableEntryGetFirst(PFileSystemPathMap, &entry));
+ while (entry != NULL)
+ {
+ CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
+ if (LSTRSTR(path, key) == path)
+ {
+ /* File-system handles file path */
+
+ if (bestKey == NULL || LSTRLEN(key) > LSTRLEN(bestKey))
+ {
+ /* Found a better match -- the new key is a subdirectory of the previous bestKey */
+ bestKey = key;
+ bestValue = value;
+ }
+ }
+ CHKLOG(rc, PHashTableEntryAdvance(&entry));
+ }
+ if (bestKey == NULL)
+ {
+ rc = ESR_INVALID_STATE;
+ PLogError(L("No file-system handles the specified path (%s)"), path);
+ goto CLEANUP;
+ }
+ *fileSystem = bestValue;
+ if (relativePath != NULL)
+ {
+ ESR_BOOL isAbsolute;
+
+ CHKLOG(rc, PFileSystemIsAbsolutePath(path + LSTRLEN(bestKey), &isAbsolute));
+ LSTRCPY(relativePath, L(""));
+ if (!isAbsolute)
+ {
+ /* Make sure that the relative path is relative to the root of the file-system */
+ LSTRCAT(relativePath, L("/"));
+ }
+ LSTRCAT(relativePath, path + LSTRLEN(bestKey));
+ }
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemCreatePFile(const LCHAR* filename, ESR_BOOL littleEndian, PFile** self)
+{
+ ESR_ReturnCode rc;
+ LCHAR absolutePath[P_PATH_MAX];
+ PFileSystem* fileSystem;
+ size_t len;
+
+ if (filename == NULL || self == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(absolutePath, filename);
+ lstrtrim(absolutePath);
+ len = P_PATH_MAX;
+ CHKLOG(rc, PFileSystemGetAbsolutePath(absolutePath, &len));
+ CHKLOG(rc, PFileSystemGetFS(absolutePath, &fileSystem, NULL));
+ rc = fileSystem->createPFile(fileSystem, absolutePath, littleEndian, self);
+ if (rc == ESR_NO_MATCH_ERROR)
+ rc = ESR_OPEN_ERROR;
+ if (rc != ESR_SUCCESS)
+ {
+ PLogError("%s, %s, %s", ESR_rc2str(rc), filename, absolutePath);
+ goto CLEANUP;
+ }
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemMkdir(const LCHAR* path)
+{
+ ESR_ReturnCode rc;
+ LCHAR absolutePath[P_PATH_MAX];
+ PFileSystem* fileSystem;
+ size_t len;
+
+ if (path == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(absolutePath, path);
+ lstrtrim(absolutePath);
+ len = P_PATH_MAX;
+ CHKLOG(rc, PFileSystemGetAbsolutePath(absolutePath, &len));
+ CHKLOG(rc, PFileSystemGetFS(absolutePath, &fileSystem, NULL));
+ CHK(rc, fileSystem->mkdir(fileSystem, absolutePath));
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemGetcwd(LCHAR* path, size_t* len)
+{
+ ESR_ReturnCode rc;
+
+ if (path == NULL || len == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ if (LSTRLEN(PFileSystemCurrentDirectory) + 1 > *len)
+ {
+ rc = ESR_BUFFER_OVERFLOW;
+ *len = LSTRLEN(PFileSystemCurrentDirectory) + 1;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(path, PFileSystemCurrentDirectory);
+ /* Check function postcondition */
+ passert(path[LSTRLEN(path)-1] == L('/'));
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemChdir(const LCHAR* path)
+{
+ ESR_ReturnCode rc;
+ LCHAR absolutePath[P_PATH_MAX];
+ PFileSystem* fileSystem;
+ size_t len;
+
+ if (path == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(absolutePath, path);
+ /* Ensure path ends with '/' */
+ if (absolutePath[LSTRLEN(absolutePath)-1] != L('/'))
+ LSTRCAT(absolutePath, L("/"));
+ lstrtrim(absolutePath);
+ len = P_PATH_MAX;
+ CHKLOG(rc, PFileSystemGetAbsolutePath(absolutePath, &len));
+ CHKLOG(rc, PFileSystemGetFS(absolutePath, &fileSystem, NULL));
+ rc = fileSystem->chdir(fileSystem, absolutePath);
+ if (rc != ESR_SUCCESS)
+ {
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ if (absolutePath[LSTRLEN(absolutePath)-1] != L('/'))
+ LSTRCAT(absolutePath, L("/"));
+ LSTRCPY(PFileSystemCurrentDirectory, absolutePath);
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+/**
+ * PRECONDITION: Directory names must end with '/'
+ */
+ESR_ReturnCode PFileSystemGetParentDirectory(LCHAR* path, size_t* len)
+{
+ LCHAR* lastSlash;
+ LCHAR clone[P_PATH_MAX];
+ ESR_ReturnCode rc;
+ size_t len2;
+
+ if (path == NULL || len == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ LSTRCPY(clone, path);
+ lstrtrim(clone);
+ len2 = P_PATH_MAX;
+ CHKLOG(rc, PFileSystemGetAbsolutePath(clone, &len2));
+
+ /* 1.0 - Strip filename */
+ lastSlash = LSTRRCHR(clone, L('/'));
+ if (lastSlash == NULL)
+ {
+ /* path contains only a filename */
+ LSTRCPY(path, L("../"));
+ return ESR_SUCCESS;
+ }
+ else if (lastSlash < clone + LSTRLEN(clone) - 1)
+ {
+
+ *(lastSlash + 1) = L('\0');
+ if (LSTRLEN(clone) > *len)
+ {
+ *len = LSTRLEN(clone);
+ rc = ESR_BUFFER_OVERFLOW;
+ goto CLEANUP;
+ }
+ LSTRCPY(path, clone);
+ *len = LSTRLEN(path);
+ return ESR_SUCCESS;
+ }
+
+ /* Get parent directory */
+ if (lastSlash -clone + 2 == 3 && LSTRNCMP(clone, L("../"), 3) == 0)
+ {
+ LSTRCAT(clone, L("../"));
+ if (LSTRLEN(clone) > *len)
+ {
+ *len = LSTRLEN(clone);
+ rc = ESR_BUFFER_OVERFLOW;
+ goto CLEANUP;
+ }
+ LSTRCPY(path, clone);
+ *len = LSTRLEN(path);
+ return ESR_SUCCESS;
+ }
+ if (lastSlash -clone + 1 == 2 && LSTRNCMP(clone, L("./"), 2) == 0)
+ {
+ if (LSTRLEN(L("../")) > *len)
+ {
+ *len = LSTRLEN(L("../"));
+ rc = ESR_BUFFER_OVERFLOW;
+ goto CLEANUP;
+ }
+ LSTRCPY(path, L("../"));
+ *len = LSTRLEN(path);
+ return ESR_SUCCESS;
+ }
+ else if (lastSlash == clone && LSTRNCMP(clone, L("/"), 1) == 0)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ *lastSlash = 0;
+ lastSlash = LSTRRCHR(clone, L('/'));
+ if (lastSlash != NULL)
+ {
+ *(lastSlash + 1) = 0;
+ if (LSTRLEN(clone) > *len)
+ {
+ *len = LSTRLEN(clone);
+ rc = ESR_BUFFER_OVERFLOW;
+ goto CLEANUP;
+ }
+ LSTRCPY(path, clone);
+ *len = LSTRLEN(path);
+ }
+ else
+ {
+ LSTRCPY(path, L(""));
+ *len = 0;
+ }
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemIsDirectoryPath(const LCHAR* path, ESR_BOOL* isDirectory)
+{
+ LCHAR temp[P_PATH_MAX];
+ ESR_ReturnCode rc;
+
+ passert(isDirectory != NULL);
+ LSTRCPY(temp, path);
+ lstrtrim(temp);
+ CHKLOG(rc, PFileSystemCanonicalSlashes(temp));
+ *isDirectory = temp[LSTRLEN(temp)-1] == '/';
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
diff --git a/portable/src/PFileSystemImpl.c b/portable/src/PFileSystemImpl.c
new file mode 100644
index 0000000..1b1e00b
--- /dev/null
+++ b/portable/src/PFileSystemImpl.c
@@ -0,0 +1,107 @@
+/*---------------------------------------------------------------------------*
+ * PFileSystemImpl.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "LCHAR.h"
+#include "PFileSystemImpl.h"
+#include "plog.h"
+#include "pmemory.h"
+
+#define MTAG NULL
+
+ESR_BOOL PFileSystemCreated = ESR_FALSE;
+
+/**
+ * [file path, PFileSystem*] mapping.
+ */
+PHashTable* PFileSystemPathMap = NULL;
+
+/**
+ * Portable standard input.
+ */
+PFile* PSTDIN = NULL;
+/**
+ * Portable standard output.
+ */
+PFile* PSTDOUT = NULL;
+/**
+ * Portable standard error.
+ */
+PFile* PSTDERR = NULL;
+
+/**
+ * Current working directory.
+ */
+LCHAR PFileSystemCurrentDirectory[P_PATH_MAX] = L("/");
+
+#ifdef USE_THREAD
+/* Prototype of private function */
+PORTABLE_API ESR_ReturnCode PtrdFlush();
+#endif
+
+
+ESR_ReturnCode PFileSystemCreate(void)
+{
+ ESR_ReturnCode rc;
+
+ if (PFileSystemCreated)
+ return ESR_SUCCESS;
+
+#ifdef USE_STACKTRACE
+ CHKLOG(rc, PStackTraceCreate());
+#endif
+ CHKLOG(rc, PHashTableCreate(NULL, MTAG, &PFileSystemPathMap));
+ CHKLOG(rc, PFileSystemInitializeStreamsImpl());
+ PFileSystemCreated = ESR_TRUE;
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemDestroy(void)
+{
+ ESR_ReturnCode rc;
+ LCHAR* key;
+ PHashTableEntry* entry;
+ PHashTableEntry* oldEntry;
+
+ if (!PFileSystemCreated)
+ return ESR_SUCCESS;
+ PFileSystemCreated = ESR_FALSE;
+ if (PFileSystemPathMap != NULL)
+ {
+ CHKLOG(rc, PHashTableEntryGetFirst(PFileSystemPathMap, &entry));
+ while (entry != NULL)
+ {
+ CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)NULL));
+ oldEntry = entry;
+ CHKLOG(rc, PHashTableEntryAdvance(&entry));
+ CHKLOG(rc, PHashTableEntryRemove(oldEntry));
+ FREE(key);
+ }
+ CHKLOG(rc, PHashTableDestroy(PFileSystemPathMap));
+ PFileSystemPathMap = NULL;
+ }
+ CHKLOG(rc, PFileSystemShutdownStreamsImpl());
+#ifdef USE_STACKTRACE
+ CHKLOG(rc, PStackTraceDestroy());
+#endif
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
diff --git a/portable/src/PFileWrap.c b/portable/src/PFileWrap.c
new file mode 100644
index 0000000..d7dddfe
--- /dev/null
+++ b/portable/src/PFileWrap.c
@@ -0,0 +1,513 @@
+/*---------------------------------------------------------------------------*
+ * PFileWrap.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "LCHAR.h"
+#include "pendian.h"
+#include "PFile.h"
+#include "plog.h"
+#include "pstdio.h"
+#include "ptypes.h"
+
+
+
+
+ESR_ReturnCode PFileClose( PFile *self )
+ {
+
+ fclose ( (FILE *)self );
+ return ( ESR_SUCCESS );
+ }
+
+
+
+ESR_ReturnCode PFileRead ( PFile *self, void *buffer, size_t size, size_t *count )
+ {
+ ESR_ReturnCode read_status;
+ size_t items_read;
+ int ferror_status;
+
+ items_read = fread ( buffer, size, *count, (FILE *)self );
+
+ if ( items_read > 0 )
+ {
+ read_status = ESR_SUCCESS;
+ *count = items_read;
+ }
+ else
+ {
+ ferror_status = ferror ( (FILE *)self );
+
+ if ( ferror_status == 0 )
+ {
+ read_status = ESR_SUCCESS;
+ *count = items_read;
+ }
+ else
+ {
+ read_status = ESR_READ_ERROR;
+ }
+ }
+ return ( read_status );
+ }
+
+
+
+ESR_ReturnCode PFileWrite ( PFile *self, void *buffer, size_t size, size_t *count )
+ {
+ ESR_ReturnCode write_status;
+ size_t items_written;
+
+ items_written = fwrite ( buffer, size, *count, (FILE *)self );
+
+ if ( items_written == ( *count ) )
+ {
+ write_status = ESR_SUCCESS;
+ *count = items_written;
+ }
+ else
+ {
+ write_status = ESR_READ_ERROR;
+ }
+ return ( write_status );
+ }
+
+
+
+ESR_ReturnCode PFileFlush ( PFile *self )
+ {
+ ESR_ReturnCode flush_status;
+ size_t flush_ok;
+
+ flush_ok = fflush ( (FILE *)self );
+
+ if ( flush_ok == 0 )
+ {
+ flush_status = ESR_SUCCESS;
+ }
+ else
+ {
+ flush_status = ESR_FLUSH_ERROR;
+ }
+ return ( flush_status );
+ }
+
+
+
+ESR_ReturnCode PFileSeek ( PFile *self, long offset, int origin )
+ {
+ ESR_ReturnCode seek_status;
+ size_t seek_ok;
+
+ seek_ok = fseek ( (FILE *)self, offset, origin );
+
+ if ( seek_ok == 0 )
+ {
+ seek_status = ESR_SUCCESS;
+ }
+ else
+ {
+ seek_status = ESR_SEEK_ERROR;
+ }
+ return ( seek_status );
+ }
+
+
+
+ESR_ReturnCode PFileGetPosition ( PFile *self, size_t *position )
+ {
+ ESR_ReturnCode get_status;
+ long ftell_result;
+
+ ftell_result = ftell ( (FILE *)self );
+
+ if ( ftell_result >= 0 )
+ {
+ *position = (size_t)ftell_result;
+ get_status = ESR_SUCCESS;
+ }
+ else
+ {
+ get_status = ESR_INVALID_STATE;
+ }
+ return ( get_status );
+ }
+
+
+
+ESR_ReturnCode PFileIsEOF ( PFile *self, ESR_BOOL *isEof )
+ {
+#ifdef NO_FEOF
+ long posCur; /* remember current file position */
+ long posEnd; /* end of file position */
+
+ posCur = ftell ( self );
+ fseek ( self, 0, SEEK_END );
+ posEnd = ftell ( self );
+
+ if ( posCur == posEnd )
+ *isEof = ESR_TRUE;
+ else
+ *isEof = ESR_FALSE;
+ fseek ( self, posCur, SEEK_SET ); /* restore position in file */
+#else
+ int is_eof;
+
+ is_eof = feof ( (FILE *)self );
+
+ if ( is_eof != 0 )
+ *isEof = ESR_TRUE;
+ else
+ *isEof = ESR_FALSE;
+#endif
+ return ( ESR_SUCCESS );
+ }
+
+
+
+ESR_ReturnCode PFileIsErrorSet ( PFile *self, ESR_BOOL *isError )
+ {
+ int is_error;
+
+ is_error = ferror ( (FILE *)self );
+
+ if ( is_error != 0 )
+ *isError = ESR_TRUE;
+ else
+ *isError = ESR_FALSE;
+ return ( ESR_SUCCESS );
+ }
+
+
+
+ESR_ReturnCode PFileClearError ( PFile *self )
+ {
+
+ clearerr ( (FILE *)self );
+ return ( ESR_SUCCESS );
+ }
+
+
+
+ESR_ReturnCode PFileVfprintf ( PFile *self, int *result, const LCHAR *format, va_list args )
+ {
+ int bytes_printed;
+
+ bytes_printed = vfprintf ( (FILE *)self, format, args );
+
+ if ( result != NULL )
+ *result = bytes_printed;
+ return ( ESR_SUCCESS );
+ }
+
+
+
+ESR_ReturnCode PFileFgetc ( PFile *self, LINT *result )
+ {
+ ESR_ReturnCode fgetc_status;
+ int error_status;
+
+ *result = fgetc ( (FILE *)self );
+
+ if ( ( *result ) != EOF )
+ {
+ fgetc_status = ESR_SUCCESS;
+ }
+ else
+ {
+ error_status = ferror ( (FILE *)self );
+
+ if ( error_status == 0 )
+ fgetc_status = ESR_SUCCESS;
+ else
+ fgetc_status = ESR_INVALID_STATE;
+ }
+ return ( fgetc_status );
+ }
+
+
+
+ESR_ReturnCode PFileFgets ( PFile *self, LCHAR *string, int n, LCHAR **result )
+ {
+ ESR_ReturnCode fgets_status;
+ int error_status;
+ LCHAR *temp;
+
+ temp = fgets ( string, n, (FILE *)self );
+
+ if ( temp != NULL )
+ {
+ fgets_status = ESR_SUCCESS;
+
+ if ( result != NULL )
+ *result = temp;
+ }
+ else
+ {
+ error_status = ferror ( (FILE *)self );
+
+ if ( error_status == 0 )
+ {
+ fgets_status = ESR_SUCCESS;
+
+ if ( result != NULL )
+ *result = NULL;
+ }
+ else
+ fgets_status = ESR_INVALID_STATE;
+ }
+ return ( fgets_status );
+ }
+
+
+
+PFile *pfopen ( const LCHAR *filename, const LCHAR *mode )
+ {
+ PFile *result;
+
+ result = (PFile *)fopen ( filename, mode );
+ return ( result );
+ }
+
+
+
+size_t pfread ( void *buffer, size_t size, size_t count, PFile *stream )
+ {
+ ESR_ReturnCode rc;
+
+ rc = PFileRead ( stream, buffer, size, &count );
+
+ if ( rc != ESR_SUCCESS )
+ return ( 0 );
+ return ( count );
+ }
+
+
+
+size_t pfwrite ( void *buffer, size_t size, size_t count, PFile *stream )
+ {
+ ESR_ReturnCode rc;
+
+ rc = PFileWrite ( stream, buffer, size, &count );
+ if ( rc != ESR_SUCCESS )
+ return ( 0 );
+ return ( count );
+ }
+
+
+
+int pfclose ( PFile *stream )
+ {
+
+ fclose ( (FILE *)stream );
+
+ return ( 0 );
+ }
+
+
+
+void prewind (PFile *stream)
+ {
+
+ PFileSeek ( stream, 0, SEEK_SET );
+ }
+
+
+
+int pfseek ( PFile *stream, long offset, int origin )
+ {
+ ESR_ReturnCode rc;
+
+ rc = PFileSeek ( stream, offset, origin );
+
+ if ( rc != ESR_SUCCESS )
+ return ( 1 );
+ return ( 0 );
+ }
+
+
+
+long pftell ( PFile *stream )
+ {
+ ESR_ReturnCode rc;
+ size_t result;
+
+ rc = PFileGetPosition ( stream, &result );
+
+ if ( rc != ESR_SUCCESS )
+ return ( -1 );
+ return ( result );
+ }
+
+
+
+int pfeof ( PFile *stream )
+ {
+ ESR_BOOL eof;
+
+ PFileIsEOF ( stream, &eof );
+
+ if ( ! eof )
+ return ( 0 );
+ return ( 1 );
+ }
+
+
+
+int pferror ( PFile *stream )
+ {
+ ESR_BOOL error;
+
+ PFileIsErrorSet ( stream, &error );
+
+ if ( ! error )
+ return ( 0 );
+ return ( 1 );
+ }
+
+
+
+void pclearerr ( PFile *stream )
+ {
+
+ PFileClearError ( stream );
+ }
+
+
+
+int pfflush ( PFile *stream )
+ {
+ ESR_ReturnCode rc;
+
+ rc = PFileFlush ( stream );
+
+ if ( rc != ESR_SUCCESS )
+ return ( PEOF );
+ return ( 0 );
+ }
+
+
+
+LCHAR* pfgets ( LCHAR *string, int n, PFile *self )
+ {
+ LCHAR *result;
+ ESR_ReturnCode rc;
+
+ rc = PFileFgets ( self, string, n, &result );
+
+ if ( rc != ESR_SUCCESS )
+ return ( NULL );
+ return ( result );
+ }
+
+
+
+LINT pfgetc ( PFile *self )
+ {
+ ESR_ReturnCode rc;
+ LINT result;
+
+ rc = PFileFgetc ( self, &result );
+
+ if ( rc != ESR_SUCCESS )
+ return ( PEOF );
+ return ( result );
+ }
+
+
+
+int pfprintf ( PFile *stream, const LCHAR *format, ... )
+ {
+ ESR_ReturnCode rc;
+ int result;
+ va_list args;
+
+ va_start ( args, format );
+ rc = PFileVfprintf ( stream, &result, format, args );
+ va_end ( args );
+
+ if ( rc != ESR_SUCCESS )
+ return ( -1 );
+ return ( result );
+ }
+
+
+
+int pvfprintf ( PFile *stream, const LCHAR *format, va_list argptr )
+ {
+ ESR_ReturnCode rc;
+ int result;
+
+ rc = PFileVfprintf ( stream, &result, format, argptr );
+
+ if ( rc != ESR_SUCCESS )
+ return ( -1 );
+ return ( result );
+ }
+
+
+ESR_ReturnCode pf_convert_backslashes_to_forwardslashes ( LCHAR *string_to_convert )
+ {
+ ESR_ReturnCode rc;
+ int string_status;
+
+ if ( string_to_convert != NULL )
+ {
+ string_status = lstrreplace ( string_to_convert, L('\\'), L('/') );
+
+ if ( string_status == 0 )
+ rc = ESR_SUCCESS;
+ else
+ rc = ESR_INVALID_ARGUMENT;
+ }
+ else
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ }
+ return ( rc );
+ }
+
+
+
+ESR_ReturnCode pf_is_path_absolute ( const LCHAR* input_path, ESR_BOOL* isAbsolute )
+ {
+ ESR_ReturnCode rc;
+ LCHAR path [P_PATH_MAX];
+
+ if ( isAbsolute != NULL )
+ {
+ LSTRCPY ( path, input_path );
+ rc = pf_convert_backslashes_to_forwardslashes ( path );
+
+ if ( rc == ESR_SUCCESS )
+ {
+ if ( ( path [0] == '/' ) || ( ( LISALPHA ( path [0] ) ) && ( path [1] == ':' ) && ( path [2] == '/' ) ) )
+ *isAbsolute = ESR_TRUE;
+ else
+ *isAbsolute = ESR_FALSE;
+ }
+ }
+ else
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ }
+ return ( rc );
+ }
+
diff --git a/portable/src/PStackSize.c b/portable/src/PStackSize.c
new file mode 100644
index 0000000..9679ca6
--- /dev/null
+++ b/portable/src/PStackSize.c
@@ -0,0 +1,61 @@
+/*---------------------------------------------------------------------------*
+ * PStackSize.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "pstdio.h"
+#include "PStackSize.h"
+
+#ifdef _WIN32
+
+static const char * PSTACK_BASE = NULL;
+
+/** Initialize the stack base. This should be done in the main() function.
+ * Note that the local variables of main() are not taken into account in the
+ * stack size computation. To overcome this problem, rewrite main() as a
+ * simple function that first invokes PSTACK_SIZE_INIT and then invokes the
+ * original main().
+*/
+void PSTACK_SIZE_INIT()
+{
+ PSTACK_BASE = (const char *) _alloca(0);
+}
+
+/**
+ * Computes the current stack size. The returned value is the number of bytes
+ * in the stack.
+ **/
+size_t PSTACK_SIZE_GET()
+{
+ return (PSTACK_BASE - ((const char *) _alloca(0)));
+}
+
+#else
+
+/* Insert other platform implementations here... */
+/*
+#error not supported at this time
+*/
+void PSTACK_SIZE_INIT()
+{}
+
+size_t PSTACK_SIZE_GET()
+{
+ return 0;
+}
+
+#endif
diff --git a/portable/src/UNIX/PANSIFileSystemUNIXImpl.c b/portable/src/UNIX/PANSIFileSystemUNIXImpl.c
new file mode 100644
index 0000000..2c561b1
--- /dev/null
+++ b/portable/src/UNIX/PANSIFileSystemUNIXImpl.c
@@ -0,0 +1,166 @@
+/*---------------------------------------------------------------------------*
+ * PANSIFileSystemUNIXImpl.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "errno.h"
+#include "PFileSystemImpl.h"
+#include "PANSIFileSystem.h"
+#include "PANSIFileSystemImpl.h"
+#include "phashtable.h"
+#include "LCHAR.h"
+#include "plog.h"
+
+ESR_ReturnCode PANSIFileSystemGetVirtualPathImpl(PFileSystem* self, LCHAR* path, size_t* len)
+{
+ PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self;
+ PHashTableEntry* entry;
+ LCHAR driveLetter = 0;
+ LCHAR* key;
+ LCHAR* value;
+ LCHAR* bestKey = NULL;
+ LCHAR* bestValue = NULL;
+ ESR_BOOL isAbsolute;
+ ESR_ReturnCode rc;
+
+ CHKLOG(rc, lstrtrim(path));
+ CHKLOG(rc, PFileSystemCanonicalSlashes(path));
+ CHKLOG(rc, PFileSystemIsAbsolutePath(path, &isAbsolute));
+ if (isAbsolute && path[0] != L('/'))
+ {
+ /* Skip drive letters in absolute paths */
+ driveLetter = path[0];
+ LSTRCPY(path, path + 2);
+ }
+ CHKLOG(rc, PHashTableEntryGetFirst(impl->directoryMap, &entry));
+ while (entry!=NULL)
+ {
+ CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
+ if (LSTRSTR(path, value)==path)
+ {
+ /* File-system handles file path */
+
+ if (bestValue==NULL || LSTRLEN(value) > LSTRLEN(bestValue))
+ {
+ /* Found a better match -- the new key is a subdirectory of the previous bestKey */
+ bestKey = key;
+ bestValue = value;
+ }
+ }
+ CHKLOG(rc, PHashTableEntryAdvance(&entry));
+ }
+ if (bestKey == NULL)
+ {
+ rc = ESR_INVALID_STATE;
+ PLogError(L("PANSIFileSystem does not handle the specified path: %s"), path);
+ goto CLEANUP;
+ }
+
+ /* Delete the real-path */
+ LSTRCPY(path, path + LSTRLEN(bestValue));
+ /* Insert the virtual-path */
+ CHKLOG(rc, lstrinsert(bestKey, path, 0, len));
+
+ /* Bring back the drive letter */
+ if (driveLetter!=0)
+ {
+ CHKLOG(rc, lstrinsert(L("X:/"), path, LSTRLEN(bestKey), len));
+ path[LSTRLEN(bestKey)] = driveLetter;
+ }
+ return ESR_SUCCESS;
+ CLEANUP:
+ return rc;
+}
+ESR_ReturnCode PANSIFileSystemMkdirImpl(PFileSystem* self, const LCHAR* path)
+{
+ LCHAR realPath[P_PATH_MAX];
+ size_t len;
+ ESR_ReturnCode rc;
+
+ passert(path!=NULL);
+ LSTRCPY(realPath, path);
+ len = P_PATH_MAX;
+ CHKLOG(rc, PANSIFileSystemGetRealPathImpl(self, realPath, &len));
+
+ if (mkdir(realPath, S_IRWXU|S_IRWXG|S_IRWXO ) != 0)
+ {
+ switch (errno)
+ {
+ case EEXIST:
+ return ESR_IDENTIFIER_COLLISION;
+ case ENOENT:
+ return ESR_NO_MATCH_ERROR;
+ default:
+ PLogError(L("ESR_INVALID_STATE"));
+ return ESR_INVALID_STATE;
+ }
+ }
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PANSIFileSystemGetcwdImpl(PFileSystem* self, LCHAR* path, size_t* len)
+{
+ ESR_ReturnCode rc;
+
+ if (path==NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ if (getcwd(path, *len) == NULL)
+ {
+ switch (errno)
+ {
+ case ERANGE:
+ *len = P_PATH_MAX;
+ return ESR_BUFFER_OVERFLOW;
+ case ENOMEM:
+ default:
+ PLogError(L("ESR_INVALID_STATE"));
+ return ESR_INVALID_STATE;
+ }
+ }
+
+ CHKLOG(rc, PANSIFileSystemGetVirtualPathImpl(self, path, len));
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PANSIFileSystemChdirImpl(PFileSystem* self, const LCHAR* path)
+{
+ LCHAR realPath[P_PATH_MAX];
+ size_t len;
+ ESR_ReturnCode rc;
+
+ passert(path!=NULL);
+ LSTRCPY(realPath, path);
+ len = P_PATH_MAX;
+ CHKLOG(rc, PANSIFileSystemGetRealPathImpl(self, realPath, &len));
+
+ if ((*path != '\0') && (chdir(realPath) != 0))
+ return ESR_NO_MATCH_ERROR;
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
diff --git a/portable/src/UNIX/PFileSystemUNIXImpl.c b/portable/src/UNIX/PFileSystemUNIXImpl.c
new file mode 100644
index 0000000..06655f3
--- /dev/null
+++ b/portable/src/UNIX/PFileSystemUNIXImpl.c
@@ -0,0 +1,142 @@
+/*---------------------------------------------------------------------------*
+ * PFileSystemUNIXImpl.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "PANSIFileImpl.h"
+#include "PANSIFileSystemImpl.h"
+#include "PFileSystem.h"
+#include "PFileSystemImpl.h"
+#include "PANSIFileSystem.h"
+#include "phashtable.h"
+#include "plog.h"
+#include "pmemory.h"
+
+
+#ifdef USE_THREAD
+ /* Prototype of private function */
+ PORTABLE_API ESR_ReturnCode PtrdFlush();
+#endif
+
+
+/**
+ * Initializes STDIN, STDOUT, STDERR.
+ */
+ESR_ReturnCode PFileSystemInitializeStreamsImpl(void)
+{
+ ESR_ReturnCode rc;
+ PANSIFileImpl* impl;
+#ifdef USE_THREAD
+ ESR_BOOL threadingEnabled;
+#endif
+ ESR_BOOL isLittleEndian;
+ PANSIFileSystemImpl* ANSIImpl = NULL;
+
+#if __BYTE_ORDER==__LITTLE_ENDIAN
+ isLittleEndian = ESR_TRUE;
+#else
+ isLittleEndian = ESR_FALSE;
+#endif
+ CHKLOG(rc, PANSIFileSystemCreate());
+ ANSIImpl = (PANSIFileSystemImpl*) PANSIFileSystemSingleton;
+ CHKLOG(rc, PMemSetLogEnabled(ESR_FALSE));
+ CHKLOG(rc, PHashTablePutValue(PFileSystemPathMap, L("/"), PANSIFileSystemSingleton, NULL));
+ CHKLOG(rc, PHashTablePutValue(ANSIImpl->directoryMap, L("/"), L("/"), NULL));
+ CHKLOG(rc, PANSIFileSystemSingleton->createPFile(PANSIFileSystemSingleton, L("/dev/stdin"), isLittleEndian, &PSTDIN));
+ impl = (PANSIFileImpl*) PSTDIN;
+ impl->value = stdin;
+
+ CHKLOG(rc, PANSIFileSystemSingleton->createPFile(PANSIFileSystemSingleton, L("/dev/stdout"), isLittleEndian, &PSTDOUT));
+ impl = (PANSIFileImpl*) PSTDOUT;
+ setvbuf(stdout, NULL, _IONBF, 0);
+ impl->value = stdout;
+
+ CHKLOG(rc, PANSIFileSystemSingleton->createPFile(PANSIFileSystemSingleton, L("/dev/stderr"), isLittleEndian, &PSTDERR));
+ impl = (PANSIFileImpl*) PSTDERR;
+ setvbuf(stderr, NULL, _IONBF, 0);
+ impl->value = stderr;
+
+ #ifdef USE_THREAD
+ /* Have STDERR and STDOUT share the same lock */
+ CHKLOG(rc, PtrdIsEnabled(&threadingEnabled));
+ if (threadingEnabled)
+ {
+ CHKLOG(rc, PtrdMonitorDestroy(impl->Interface.lock));
+ impl->Interface.lock = ((PANSIFileImpl*) PSTDOUT)->Interface.lock;
+ }
+ #endif
+ CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, L("/"), NULL));
+ CHKLOG(rc, PHashTableRemoveValue(ANSIImpl->directoryMap, L("/"), NULL));
+ CHKLOG(rc, PMemSetLogEnabled(ESR_TRUE));
+ return ESR_SUCCESS;
+CLEANUP:
+ PHashTableRemoveValue(PFileSystemPathMap, L("/"), NULL);
+ if (ANSIImpl!=NULL)
+ PHashTableRemoveValue(ANSIImpl->directoryMap, L("/"), NULL);
+ PMemSetLogEnabled(ESR_TRUE);
+ return rc;
+}
+
+ESR_ReturnCode PFileSystemShutdownStreamsImpl(void)
+{
+ ESR_ReturnCode rc;
+ PANSIFileImpl* impl;
+
+ /* It is illegal to log to file after the file system has shutdown so we do it now */
+#ifdef USE_THREAD
+ PtrdFlush();
+#endif
+ PMemDumpLogFile();
+
+ if (PSTDIN!=NULL)
+ {
+ CHKLOG(rc, PFileFlush(PSTDIN));
+ impl = (PANSIFileImpl*) PSTDIN;
+ impl->value = NULL;
+ CHKLOG(rc, PFileDestroy(PSTDIN));
+ PSTDIN = NULL;
+ }
+ if (PSTDOUT!=NULL)
+ {
+#ifdef USE_THREAD
+ if (PSTDERR!=NULL)
+ {
+ /* stdout, stderr share the same lock, only one of them should destroy it */
+ PFileImpl* impl = (PFileImpl*) PSTDOUT;
+
+ impl->lock = NULL;
+ }
+#endif
+ CHKLOG(rc, PFileFlush(PSTDOUT));
+ impl = (PANSIFileImpl*) PSTDOUT;
+ impl->value = NULL;
+ CHKLOG(rc, PFileDestroy(PSTDOUT));
+ PSTDOUT = NULL;
+ }
+ if (PSTDERR!=NULL)
+ {
+ CHKLOG(rc, PFileFlush(PSTDERR));
+ impl = (PANSIFileImpl*) PSTDERR;
+ impl->value = NULL;
+ CHKLOG(rc, PFileDestroy(PSTDERR));
+ PSTDERR = NULL;
+ }
+ CHKLOG(rc, PANSIFileSystemDestroy());
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
diff --git a/portable/src/UNIX/PFileWrapUNIX_OS_Specific.c b/portable/src/UNIX/PFileWrapUNIX_OS_Specific.c
new file mode 100644
index 0000000..dfe2efe
--- /dev/null
+++ b/portable/src/UNIX/PFileWrapUNIX_OS_Specific.c
@@ -0,0 +1,116 @@
+/*---------------------------------------------------------------------------*
+ * PFileWrapUNIX_OS_Specific.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "errno.h"
+#include "PFileSystemImpl.h"
+#include "PANSIFileSystem.h"
+#include "PANSIFileSystemImpl.h"
+#include "phashtable.h"
+#include "LCHAR.h"
+#include "plog.h"
+
+ESR_ReturnCode pf_make_dir ( const LCHAR* path )
+ {
+ ESR_ReturnCode rc;
+
+ passert(path!=NULL);
+
+ if ( mkdir ( path, S_IRWXU|S_IRWXG|S_IRWXO ) == 0)
+ {
+ rc = ESR_SUCCESS;
+ }
+ else
+ {
+ switch (errno)
+ {
+ case EEXIST:
+ rc = ESR_IDENTIFIER_COLLISION;
+ break;
+
+ case ENOENT:
+ rc = ESR_NO_MATCH_ERROR;
+ break;
+
+ default:
+ PLogError ( L("ESR_INVALID_STATE") );
+ rc = ESR_INVALID_STATE;
+ break;
+ }
+ }
+ return ( rc );
+ }
+
+
+
+ESR_ReturnCode pf_get_cwd ( LCHAR* path, size_t *len )
+ {
+ ESR_ReturnCode rc;
+
+ if ( path != NULL )
+ {
+ if ( getcwd ( path, *len ) != NULL)
+ {
+ rc = ESR_SUCCESS;
+ }
+ else
+ {
+ switch ( errno )
+ {
+ case ERANGE:
+ rc = ESR_BUFFER_OVERFLOW;
+ break;
+
+ case ENOMEM:
+ rc = ESR_OUT_OF_MEMORY;
+ break;
+
+ default:
+ PLogError(L("ESR_INVALID_STATE"));
+ rc = ESR_INVALID_STATE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ }
+
+ return ( rc );
+ }
+
+
+
+ESR_ReturnCode pf_change_dir ( const LCHAR* path )
+ {
+ ESR_ReturnCode rc;
+
+ passert ( path != NULL );
+ passert ( *path != '\0' );
+
+ if ( chdir ( path ) == 0 )
+ rc = ESR_SUCCESS;
+ else
+ rc = ESR_NO_MATCH_ERROR;
+ return ( rc );
+ }
diff --git a/portable/src/pLastError.c b/portable/src/pLastError.c
new file mode 100644
index 0000000..446be08
--- /dev/null
+++ b/portable/src/pLastError.c
@@ -0,0 +1,65 @@
+/*---------------------------------------------------------------------------*
+ * pLastError.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "pLastError.h"
+#include "plog.h"
+
+void printGetLastErrorInternal(const LCHAR* text, char* file, int line)
+{
+#ifdef _WIN32
+ LCHAR* msg;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ (LPTSTR) &msg,
+ 0,
+ NULL))
+ {
+ ESR_BOOL isInit;
+ ESR_ReturnCode rc;
+ msg[LSTRLEN(msg)-2] = L('\0'); /* cut off newline character */
+
+ rc = PLogIsInitialized(&isInit);
+ if (rc != ESR_SUCCESS)
+ isInit = FALSE;
+ if (isInit)
+ PLogError(L("%s: %s"), text, msg);
+ else
+ pfprintf(PSTDERR, L("[%s:%d] %s: %s\n"), file, line, text, msg);
+ LocalFree(msg);
+ }
+#elif defined(__vxworks)
+ int err;
+
+ err = errnoGet(); /* get the error status value of the calling task */
+#ifndef NDEBUG
+ /* printErrno(err); */ /* need special flag to build Simulator */
+#endif
+ pfprintf(PSTDERR, "[%s:%d] %s, errno = %x\n", file, line, text, err);
+
+#elif (OS == OS_UNIX)
+
+#else
+#error("Have not implemented yet!!!")
+#endif
+}
diff --git a/portable/src/pcputimer.c b/portable/src/pcputimer.c
new file mode 100644
index 0000000..3338475
--- /dev/null
+++ b/portable/src/pcputimer.c
@@ -0,0 +1,238 @@
+/*---------------------------------------------------------------------------*
+ * pcputimer.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#include "pcputimer.h"
+#include "pmemory.h"
+
+#if defined(_WIN32)
+
+/*
+ Note that this implementation assumes that GetThreadTimes is
+ available (requires NT 3.5 and above) and that 64 bit arithmetic is
+ available (requires VC)
+*/
+
+struct PCPUTimer_t
+{
+ HANDLE hThread;
+ LARGE_INTEGER RefTime;
+ asr_uint32_t elapsed;
+};
+
+
+/**
+ * Creates a new timer object.
+ **/
+ESR_ReturnCode PCPUTimerCreate(PCPUTimer **timer)
+{
+ PCPUTimer *tmp = NULL;
+
+ if (timer == NULL)
+ return ESR_INVALID_ARGUMENT;
+ tmp = NEW(PCPUTimer, "PCPUTimer");
+ if (tmp == NULL) return ESR_OUT_OF_MEMORY;
+
+ tmp->hThread = GetCurrentThread();
+ tmp->RefTime.QuadPart = -1;
+ tmp->elapsed = 0;
+ *timer = tmp;
+
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PCPUTimerDestroy(PCPUTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ FREE(timer);
+ return ESR_SUCCESS;
+}
+
+/**
+ * Starts the timer. This sets the reference time from which all new elapsed
+ * time are computed. This does not reset the elapsed time to 0. This is
+ * useful to pause the timer.
+ **/
+ESR_ReturnCode PCPUTimerStart(PCPUTimer *timer)
+{
+ FILETIME CreationTime;
+ FILETIME ExitTime;
+ FILETIME KernelTime;
+ FILETIME UserTime;
+
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ if (!GetThreadTimes(timer->hThread,
+ &CreationTime, &ExitTime, &KernelTime, &UserTime))
+ {
+ return ESR_FATAL_ERROR;
+ }
+
+ timer->RefTime.QuadPart = (((LARGE_INTEGER*) & KernelTime)->QuadPart +
+ ((LARGE_INTEGER*) & UserTime)->QuadPart);
+
+ return ESR_SUCCESS;
+}
+
+/**
+ * Stops the timer.
+ **/
+ESR_ReturnCode PCPUTimerStop(PCPUTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ if (timer->RefTime.QuadPart != -1)
+ {
+ FILETIME CreationTime;
+ FILETIME ExitTime;
+ FILETIME KernelTime;
+ FILETIME UserTime;
+
+ if (!GetThreadTimes(timer->hThread,
+ &CreationTime, &ExitTime, &KernelTime, &UserTime))
+ return ESR_FATAL_ERROR;
+
+ timer->elapsed =
+ (asr_uint32_t) (((LARGE_INTEGER*) &KernelTime)->QuadPart +
+ ((LARGE_INTEGER*) &UserTime)->QuadPart -
+ timer->RefTime.QuadPart) / 10;
+ }
+ return ESR_SUCCESS;
+}
+
+/**
+ * Returns the timer elapsed time. If the Timer is in the stopped state,
+ * successive calls to getElapsed() will always return the same value. If
+ * the Timer is in the started state, successive calls will return the
+ * elapsed time since the last time PCPUTimerStart() was called.
+ */
+ESR_ReturnCode PCPUTimerGetElapsed(PCPUTimer *timer, asr_uint32_t *elapsed)
+{
+ if (timer == NULL || elapsed == NULL) return ESR_INVALID_ARGUMENT;
+ if (timer->RefTime.QuadPart != -1)
+ {
+ FILETIME CreationTime;
+ FILETIME ExitTime;
+ FILETIME KernelTime;
+ FILETIME UserTime;
+
+ if (!GetThreadTimes(timer->hThread,
+ &CreationTime, &ExitTime, &KernelTime, &UserTime))
+ return ESR_FATAL_ERROR;
+
+ *elapsed = timer->elapsed +
+ (asr_uint32_t)(((LARGE_INTEGER*) & KernelTime)->QuadPart +
+ ((LARGE_INTEGER*) & UserTime)->QuadPart -
+ timer->RefTime.QuadPart) / 10;
+ }
+ else
+ *elapsed = timer->elapsed;
+ return ESR_SUCCESS;
+}
+
+
+/**
+ * Resets the elapsed time to 0 and resets the reference time of the Timer.
+ * This effectively reset the timer in the same state it was right after creation.
+ **/
+ESR_ReturnCode PCPUTimerReset(PCPUTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ timer->RefTime.QuadPart = -1;
+ timer->elapsed = 0;
+ return ESR_SUCCESS;
+}
+
+#elif defined(POSIX)
+/*
+*/
+
+struct PCPUTimer_t
+{
+ HANDLE hThread;
+ asr_uint32_t RefTime;
+ asr_uint32_t elapsed;
+};
+
+/**
+* Creates a new timer object.
+**/
+ESR_ReturnCode PCPUTimerCreate(PCPUTimer **timer)
+{
+ PCPUTimer *tmp = NULL;
+
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ tmp = NEW(PCPUTimer, "PCPUTimer");
+ if (tmp == NULL) return ESR_OUT_OF_MEMORY;
+
+ tmp->hThread = (HANDLE)pthread_self();
+ tmp->elapsed = 0;
+ *timer = tmp;
+
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PCPUTimerDestroy(PCPUTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ FREE(timer);
+ return ESR_SUCCESS;
+}
+
+/**
+* Starts the timer. This sets the reference time from which all new elapsed
+* time are computed. This does not reset the elapsed time to 0. This is
+* useful to pause the timer.
+**/
+ESR_ReturnCode PCPUTimerStart(PCPUTimer *timer)
+{
+ return ESR_SUCCESS;
+}
+
+/**
+* Stops the timer.
+**/
+ESR_ReturnCode PCPUTimerStop(PCPUTimer *timer)
+{
+ return ESR_SUCCESS;
+}
+
+/**
+* Returns the timer elapsed time. If the Timer is in the stopped state,
+* successive calls to getElapsed() will always return the same value. If
+* the Timer is in the started state, successive calls will return the
+* elapsed time since the last time PCPUTimerStart() was called.
+*/
+ESR_ReturnCode PCPUTimerGetElapsed(PCPUTimer *timer, asr_uint32_t *elapsed)
+{
+ return ESR_SUCCESS;
+}
+
+
+/**
+* Resets the elapsed time to 0 and resets the reference time of the Timer.
+* This effectively reset the timer in the same state it was right after creation.
+**/
+ESR_ReturnCode PCPUTimerReset(PCPUTimer *timer)
+{
+ return ESR_SUCCESS;
+}
+
+#else
+/* #error "Ptimer not implemented for this platform." */
+#endif
diff --git a/portable/src/pcrc.c b/portable/src/pcrc.c
new file mode 100644
index 0000000..a178fd8
--- /dev/null
+++ b/portable/src/pcrc.c
@@ -0,0 +1,159 @@
+/*---------------------------------------------------------------------------*
+ * pcrc.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#include "pcrc.h"
+#include <limits.h>
+
+/* the CRC tables are computed by the crctable.c program which is part of this
+ distribution but not compiled.
+ */
+
+#if (UINT_MAX >= 0xFFFFFFFFU)
+
+#define WIDTH 32
+
+/* USE CRC-32 algorithm on machine with at least 32 bits. */
+#define POLYNOMIAL 0x04C11DB7
+
+static unsigned int crcTable[] =
+ {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+ 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+ 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+ 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+ 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+ 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+ 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+ 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+ 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+ 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+ 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+ 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+ 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+ 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+ 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+ 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+ 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+ 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+ 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+ 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+ 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+ 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+ };
+
+#elif (UINT_MAX >= 0xFFFFU)*/
+/* use CRC-16 on machine with [16..32[ bits integer. */
+
+#define WIDTH 16
+#define TOPBIT (1 << (WIDTH - 1))
+
+#define POLYNOMIAL 0x8005
+
+static unsigned int crcTable[] =
+ {
+ 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
+ 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
+ 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
+ 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
+ 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
+ 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
+ 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
+ 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
+ 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
+ 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
+ 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
+ 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
+ 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
+ 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
+ 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
+ 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
+ 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
+ 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
+ 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
+ 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
+ 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
+ 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
+ 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
+ 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
+ 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
+ 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
+ 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
+ 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
+ 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
+ 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
+ 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
+ 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
+ };
+
+#else
+#error "CRC is not defined on machine with less than 16 bits arithmetic."
+#endif
+
+unsigned int pcrcComputeData(const void *data, unsigned int size)
+{
+ return pcrcUpdateData(CRC_INITIAL_VALUE, data, size);
+}
+
+unsigned int pcrcUpdateData(unsigned int crc, const void *data, unsigned int size)
+{
+ register unsigned char byte;
+ register const unsigned char *p = (const unsigned char *) data;
+ register unsigned int remainder = crc;
+
+ if (p != NULL)
+ {
+ while (size > 0)
+ {
+#if CHAR_BIT <= 8
+ byte = (unsigned char)((remainder >> (WIDTH - 8)) ^ *p++);
+ remainder = crcTable[byte] ^(remainder << 8);
+#elif CHAR_BIT <= 16
+ byte = (unsigned char)(((remainder >> (WIDTH - 8)) ^(*p >> 8)) & 0xFF);
+ remainder = crcTable[byte] ^(remainder << 8);
+ byte = (unsigned char)(((remainder >> (WIDTH - 8)) ^(*p++ & 0xFF)) & 0xFF);
+ remainder = crcTable[byte] ^(remainder << 8);
+#else
+#error "crcCompute not defined for this platform."
+#endif
+ --size;
+ }
+ }
+
+ return remainder;
+}
+
+unsigned int pcrcComputeString(const LCHAR *str)
+{
+ if (str == NULL)
+ return pcrcComputeData(NULL, 0);
+
+ return pcrcComputeData(str, sizeof(LCHAR) * LSTRLEN(str));
+}
diff --git a/portable/src/pendian.c b/portable/src/pendian.c
new file mode 100644
index 0000000..3649ab0
--- /dev/null
+++ b/portable/src/pendian.c
@@ -0,0 +1,49 @@
+/*---------------------------------------------------------------------------*
+ * pendian.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+
+
+
+#include "pendian.h"
+
+void swap_byte_order(void *buffer, size_t count, size_t itemSize)
+{
+ char *data = (char *) buffer;
+ register char *p, *q, c;
+
+ /* Process every item */
+ while (count > 0)
+ {
+ p = data;
+ q = data + itemSize - 1;
+
+ while (p < q)
+ {
+ c = *p;
+ *p++ = *q;
+ *q-- = c;
+ }
+
+ /* Prepare for next pass */
+ data += itemSize;
+ count--;
+ }
+}
diff --git a/portable/src/phashtable.c b/portable/src/phashtable.c
new file mode 100644
index 0000000..4940c60
--- /dev/null
+++ b/portable/src/phashtable.c
@@ -0,0 +1,560 @@
+/*---------------------------------------------------------------------------*
+ * phashtable.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+
+
+
+#include <string.h>
+
+#include "phashtable.h"
+#include "plog.h"
+#include "pmemory.h"
+#include "pstdio.h"
+
+//extern int strcmp(const char * s1, const char * s2);
+
+#define ALLOC_SIZE 16
+
+struct PHashTableEntry_t
+{
+ const void *key;
+ const void *value;
+ PHashTable *table;
+ unsigned int idx;
+ PHashTableEntry *next;
+ PHashTableEntry *prev;
+ unsigned int hashCode;
+};
+
+typedef struct PHashTableEntryBlock_t
+{
+ PHashTableEntry entries[ALLOC_SIZE];
+ struct PHashTableEntryBlock_t *next;
+}
+PHashTableEntryBlock;
+
+
+struct PHashTable_t
+{
+ PHashTableArgs args;
+ const LCHAR *memoryTag;
+ unsigned int size;
+ float maxLoadFactor;
+ PHashTableEntry **entries;
+ unsigned int threshold;
+ PHashTableEntry *freeList;
+ PHashTableEntryBlock *entryBlock;
+};
+
+#include "pcrc.h"
+
+static unsigned int hashString(const void *key)
+{
+ return ~pcrcComputeString(key);
+}
+
+ESR_ReturnCode PHashTableCreate(PHashTableArgs *args,
+ const LCHAR *memTag,
+ PHashTable **table)
+{
+ PHashTable *tmp;
+ unsigned int i;
+
+ if (table == NULL ||
+ (args != NULL && args->maxLoadFactor <= 0.0))
+ return ESR_INVALID_ARGUMENT;
+
+
+ if ((tmp = NEW(PHashTable, memTag)) == NULL)
+ return ESR_OUT_OF_MEMORY;
+
+ if (args == NULL)
+ {
+ tmp->args.capacity = PHASH_TABLE_DEFAULT_CAPACITY;
+ tmp->args.maxLoadFactor = PHASH_TABLE_DEFAULT_MAX_LOAD_FACTOR;
+ tmp->args.hashFunction = PHASH_TABLE_DEFAULT_HASH_FUNCTION;
+ tmp->args.compFunction = PHASH_TABLE_DEFAULT_COMP_FUNCTION;
+ }
+ else
+ {
+ memcpy(&tmp->args, args, sizeof(PHashTableArgs));
+ }
+ if (tmp->args.hashFunction == PHASH_TABLE_DEFAULT_HASH_FUNCTION)
+ tmp->args.hashFunction = hashString;
+
+ if (tmp->args.compFunction == PHASH_TABLE_DEFAULT_COMP_FUNCTION)
+ tmp->args.compFunction = LSTRCMP;
+
+ tmp->entries = NEW_ARRAY(PHashTableEntry *, tmp->args.capacity, memTag);
+
+ if (tmp->entries == NULL)
+ {
+ FREE(tmp);
+ return ESR_OUT_OF_MEMORY;
+ }
+
+ for (i = tmp->args.capacity; i > 0;)
+ {
+ tmp->entries[--i] = NULL;
+ }
+
+ tmp->memoryTag = memTag;
+ tmp->size = 0;
+ tmp->threshold = (unsigned int)(tmp->args.capacity * tmp->args.maxLoadFactor);
+ tmp->freeList = NULL;
+ tmp->entryBlock = NULL;
+
+ *table = tmp;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PHashTableDestroy(PHashTable *table)
+{
+ PHashTableEntryBlock *tmp, *block;
+
+ if (table == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ block = table->entryBlock;
+ while (block != NULL)
+ {
+ tmp = block->next;
+ FREE(block);
+ block = tmp;
+ }
+
+ FREE(table->entries);
+ FREE(table);
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PHashTableGetSize(PHashTable *table,
+ size_t *size)
+{
+ if (table == NULL || size == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ *size = table->size;
+ return ESR_SUCCESS;
+}
+
+static PHashTableEntry *getEntry(PHashTable *table,
+ const void *key,
+ unsigned int hashCode,
+ unsigned int idx)
+{
+ PHashTableEntry *entry = table->entries[idx];
+
+ if (key == NULL)
+ {
+ while (entry != NULL)
+ {
+ if (entry->key == NULL)
+ return entry;
+
+ entry = entry->next;
+ }
+ }
+ else
+ {
+ while (entry != NULL)
+ {
+ if (entry->hashCode == hashCode && table->args.compFunction(key, entry->key) == 0)
+ return entry;
+
+ entry = entry->next;
+ }
+ }
+
+ return NULL;
+}
+
+static void removeEntry(PHashTableEntry *entry)
+{
+ if (entry->prev == NULL)
+ entry->table->entries[entry->idx] = entry->next;
+ else
+ entry->prev->next = entry->next;
+
+ if (entry->next != NULL)
+ entry->next->prev = entry->prev;
+
+ entry->table->size--;
+
+ entry->next = entry->table->freeList;
+ entry->table->freeList = entry;
+ /* clean up entry for re-use. */
+ entry->key = entry->value = NULL;
+}
+
+ESR_ReturnCode PHashTableGetValue(PHashTable *table, const void *key, void **value)
+{
+ PHashTableEntry *entry;
+ unsigned int hashCode;
+ unsigned int idx;
+
+ if (table == NULL || value == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ hashCode = table->args.hashFunction(key);
+ idx = hashCode % table->args.capacity;
+ if ((entry = getEntry(table, key, hashCode, idx)) != NULL)
+ {
+ *value = (void *) entry->value;
+ return ESR_SUCCESS;
+ }
+ else
+ {
+ *value = NULL;
+ return ESR_NO_MATCH_ERROR;
+ }
+}
+
+ESR_ReturnCode PHashTableContainsKey(PHashTable *table, const void *key, ESR_BOOL* exists)
+{
+ ESR_ReturnCode rc;
+ PHashTableEntry* entry;
+
+ if (table == NULL || exists == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ rc = PHashTableGetEntry(table, key, &entry);
+ if (rc == ESR_SUCCESS)
+ *exists = ESR_TRUE;
+ else if (rc == ESR_NO_MATCH_ERROR)
+ *exists = ESR_FALSE;
+ else
+ goto CLEANUP;
+
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PHashTableGetEntry(PHashTable *table, const void *key, PHashTableEntry **entry)
+{
+ unsigned int hashCode;
+ unsigned int idx;
+ PHashTableEntry* result;
+
+ if (table == NULL || entry == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ hashCode = table->args.hashFunction(key);
+ idx = hashCode % table->args.capacity;
+
+ result = getEntry(table, key, hashCode, idx);
+ if (result == NULL)
+ return ESR_NO_MATCH_ERROR;
+ *entry = result;
+ return ESR_SUCCESS;
+}
+
+static ESR_ReturnCode PHashTableRehash(PHashTable *table)
+{
+ unsigned int i, idx;
+ unsigned int oldCapacity = table->args.capacity;
+ unsigned int newCapacity = ((oldCapacity << 1) | 0x01);
+ PHashTableEntry *entry, *tmp, *next;
+
+ PHashTableEntry **newEntries =
+ (PHashTableEntry **)
+ REALLOC(table->entries,
+ sizeof(PHashTableEntry *) * newCapacity);
+
+ if (newEntries == NULL)
+ return ESR_OUT_OF_MEMORY;
+
+ table->entries = newEntries;
+ table->args.capacity = newCapacity;
+ table->threshold = (unsigned int)(newCapacity * table->args.maxLoadFactor);
+
+ for (i = oldCapacity; i < newCapacity; ++i)
+ {
+ table->entries[i] = NULL;
+ }
+
+ for (i = 0; i < oldCapacity; i++)
+ {
+ for (entry = table->entries[i]; entry != NULL;)
+ {
+ idx = entry->hashCode % newCapacity;
+ if (idx != i)
+ {
+ /* Need to change location. */
+ entry->idx = idx;
+
+ next = entry->next;
+
+ if (entry->prev != NULL)
+ entry->prev->next = next;
+ else
+ table->entries[i] = next;
+
+ if (next != NULL)
+ next->prev = entry->prev;
+
+ tmp = table->entries[idx];
+ entry->next = tmp;
+ entry->prev = NULL;
+ if (tmp != NULL)
+ tmp->prev = entry;
+ table->entries[idx] = entry;
+
+ entry = next;
+ }
+ else
+ {
+ /* Already in the right slot. */
+ entry = entry->next;
+ }
+ }
+ }
+ return ESR_SUCCESS;
+}
+
+
+ESR_ReturnCode PHashTablePutValue(PHashTable *table,
+ const void *key,
+ const void *value,
+ void **oldValue)
+{
+ ESR_ReturnCode rc = ESR_SUCCESS;
+ unsigned int hashCode, idx;
+ PHashTableEntry *entry;
+
+ if (table == NULL) return ESR_INVALID_ARGUMENT;
+ hashCode = table->args.hashFunction(key);
+ idx = hashCode % table->args.capacity;
+
+ entry = getEntry(table, key, hashCode, idx);
+ if (entry != NULL)
+ {
+ if (oldValue != NULL) *oldValue = (void *) entry->value;
+ entry->value = value;
+ return ESR_SUCCESS;
+ }
+
+ /* If we get here, we need to add a new entry. But first, verify if we need
+ to rehash. */
+ if (table->size >= table->threshold)
+ {
+ if ((rc = PHashTableRehash(table)) != ESR_SUCCESS)
+ return rc;
+ idx = hashCode % table->args.capacity;
+ }
+
+ if (table->freeList == NULL)
+ {
+ /* Allocate a new block and put all entries on the free list. */
+ PHashTableEntryBlock *block;
+ int i;
+
+ block = NEW(PHashTableEntryBlock, table->memoryTag);
+ if (block == NULL)
+ return ESR_OUT_OF_MEMORY;
+
+ block->next = table->entryBlock;
+ table->entryBlock = block;
+
+ for (i = 0; i < ALLOC_SIZE - 1; ++i)
+ {
+ block->entries[i].next = &block->entries[i+1];
+ }
+ block->entries[ALLOC_SIZE-1].next = NULL;
+
+ /* do not see any bug in following code. But on the VxWorks with optimization option -O3
+ it produces wrong result: block->entries[0].next is correct but block->entries[1].next = NULL
+ it causes lot of memory wastes.
+ for (i = 0, entry = block->entries; i < ALLOC_SIZE - 1; ++i, ++entry)
+ {
+ entry->next = entry+1;
+ }
+ entry->next = table->freeList;
+ */
+
+ table->freeList = block->entries;
+ }
+
+ /* Get an entry from the freeList. */
+ entry = table->freeList;
+ table->freeList = entry->next;
+
+ /* Initialize entry data structure. */
+ entry->table = table;
+ entry->idx = idx;
+ entry->key = key;
+ entry->value = value;
+ entry->hashCode = hashCode;
+ entry->next = table->entries[idx];
+ entry->prev = NULL;
+ if (entry->next != NULL)
+ entry->next->prev = entry;
+ table->entries[idx] = entry;
+ table->size++;
+
+ if (oldValue != NULL) *oldValue = NULL;
+ return ESR_SUCCESS;
+}
+
+
+ESR_ReturnCode PHashTableRemoveValue(PHashTable *table,
+ const void *key,
+ void **oldValue)
+{
+ unsigned int hashCode, idx;
+ PHashTableEntry *entry;
+ ESR_ReturnCode rc;
+
+ if (table == NULL)
+ {
+ rc = ESR_INVALID_ARGUMENT;
+ PLogError(ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+
+ hashCode = table->args.hashFunction(key);
+ idx = hashCode % table->args.capacity;
+
+ entry = getEntry(table, key, hashCode, idx);
+ if (entry != NULL)
+ {
+ if (oldValue != NULL)
+ *oldValue = (void*) entry->value;
+ removeEntry(entry);
+ }
+ else
+ {
+ if (oldValue != NULL)
+ *oldValue = NULL;
+ }
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+
+ESR_ReturnCode PHashTableEntryGetKeyValue(PHashTableEntry *entry,
+ void **key,
+ void **value)
+{
+ if (entry == NULL) return ESR_INVALID_ARGUMENT;
+
+ if (key != NULL) *key = (void *) entry->key;
+ if (value != NULL) *value = (void *) entry->value;
+ return ESR_SUCCESS;
+}
+
+
+/**
+ * Sets the value associated with this entry.
+ * @param entry The hashtable entry.
+ * @param value The value to associate with the entry.
+ * @param oldvalue If this pointer is non-NULL, it will be set to the previous value associated with this entry.
+ **/
+ESR_ReturnCode PHashTableEntrySetValue(PHashTableEntry *entry,
+ const void *value,
+ void **oldValue)
+{
+ if (entry == NULL) return ESR_INVALID_ARGUMENT;
+
+ if (oldValue != NULL) *oldValue = (void *) entry->value;
+ entry->value = value;
+ return ESR_SUCCESS;
+}
+
+
+/**
+ * Removes the entry from its hash table.
+ *
+ * @param entry The hashtable entry.
+ **/
+ESR_ReturnCode PHashTableEntryRemove(PHashTableEntry *entry)
+{
+ if (entry == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ removeEntry(entry);
+
+ return ESR_SUCCESS;
+}
+
+static PHashTableEntry* iteratorAdvance(PHashTable *table, PHashTableEntry *entry)
+{
+ unsigned int idx;
+
+ if (entry != NULL)
+ {
+ idx = entry->idx;
+ entry = entry->next;
+ if (entry == NULL)
+ {
+ while (++idx < table->args.capacity)
+ {
+ if (table->entries[idx] != NULL)
+ {
+ entry = table->entries[idx];
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (idx = 0; idx < table->args.capacity; ++idx)
+ {
+ if (table->entries[idx] != NULL)
+ {
+ entry = table->entries[idx];
+ break;
+ }
+ }
+ }
+ return entry;
+}
+
+
+ESR_ReturnCode PHashTableEntryGetFirst(PHashTable *table, PHashTableEntry **entry)
+{
+ if (table == NULL || entry == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ *entry = iteratorAdvance(table, NULL);
+ return ESR_SUCCESS;
+}
+
+/**
+ * Iterates on the next key and value. Returns a NULL key when at the end of the hash table.
+ *
+ * @param iter The iterator on which the iteration is performed.
+ * @param key Returns the key associated with the entry, cannot be NULL.
+ * @param value If non-NULL, returns the value associated with the entry.
+ **/
+ESR_ReturnCode PHashTableEntryAdvance(PHashTableEntry **entry)
+{
+ if (entry == NULL || *entry == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ *entry = iteratorAdvance((*entry)->table, *entry);
+ return ESR_SUCCESS;
+}
diff --git a/portable/src/plog.c b/portable/src/plog.c
new file mode 100644
index 0000000..3aefbc7
--- /dev/null
+++ b/portable/src/plog.c
@@ -0,0 +1,538 @@
+/*---------------------------------------------------------------------------*
+ * plog.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "PFileSystem.h"
+#include "ptypes.h"
+#include "plog.h"
+#include "pmemory.h"
+#include "pstdio.h"
+#include "ptimestamp.h"
+#include "passert.h"
+#ifdef USE_STACKTRACE
+#include "PStackTrace.h"
+#endif
+
+#ifdef USE_THREAD
+#include "ptrd.h"
+#include "pmutex.h"
+#endif
+
+
+#if defined (ANDROID)
+#if defined (HAVE_ANDROID_OS)
+#define LOG_TAG "Srec"
+#include <utils/Log.h>
+#endif
+#endif
+
+#include "phashtable.h"
+
+#define MTAG __FILE__
+
+#define FILTER_MSG_1 "ESR_BUFFER_OVERFLOW"
+#define FILTER_MSG_1_SIZE ( sizeof ( FILTER_MSG_1 ) - 1 )
+
+#define FILTER_MSG_2 "ESR_NO_MATCH_ERROR"
+#define FILTER_MSG_2_SIZE ( sizeof ( FILTER_MSG_2 ) - 1 )
+
+static unsigned int GlogLevel = 0;
+static PLogger *Glogger = NULL;
+static LOG_OUTPUT_FORMAT GlogFormat = LOG_OUTPUT_FORMAT_MODULE_NAME |
+ LOG_OUTPUT_FORMAT_DATE_TIME;
+/**
+ * Used to detect endless recursion where the PLog module calls itself.
+ */
+static ESR_BOOL locked = ESR_FALSE;
+#ifdef USE_THREAD
+
+static PtrdMutex* Gmutex = NULL;
+#endif
+
+typedef struct FileLogger_t
+{
+ PLogger base;
+ PFile* fp;
+}
+FileLogger;
+
+/**
+ * Prints and formats a message to the log.
+ *
+ * @param self the PLogger.
+ *
+ * @param format the format string specifying the next arguments (a la
+ * printf).
+ *
+ * @param args variable argument list.
+ *
+ * @return The number of bytes written to the PLogger or -1 if an error
+ * occurs.
+ */
+static ESR_ReturnCode FileLoggerPrintf(PLogger *self, const LCHAR *format, ...)
+{
+ FileLogger *p = STATIC_CAST(self, FileLogger, base);
+ ESR_ReturnCode rc;
+ va_list args;
+
+ va_start(args, format);
+ rc = pvfprintf(p->fp, format, args);
+ va_end(args);
+ return rc;
+}
+
+static ESR_ReturnCode FileLoggerFlush(PLogger *self)
+{
+ FileLogger *p = STATIC_CAST(self, FileLogger, base);
+ return pfflush(p->fp) == 0 ? ESR_SUCCESS : ESR_FATAL_ERROR;
+}
+
+
+/**
+ * Destroys the logger. This function is responsible to deallocate any
+ * resources used by the logger. In particular, if buffering is internally
+ * used, it needs to flush the buffer.
+ */
+static void FileLoggerDestroy(PLogger *self)
+{
+ FileLogger *p = STATIC_CAST(self, FileLogger, base);
+ pfflush(p->fp);
+
+ if (p->fp != PSTDERR && p->fp != PSTDOUT)
+ pfclose(p->fp);
+ FREE(p);
+}
+
+static ESR_ReturnCode createPFileLogger(PFile* fp, PLogger** logger)
+{
+ FileLogger* fileLogger;
+
+ if (fp == NULL)
+ return ESR_INVALID_ARGUMENT;
+ fileLogger = NEW(FileLogger, MTAG);
+ if (fileLogger == NULL)
+ return ESR_OUT_OF_MEMORY;
+
+ fileLogger->base.printf = FileLoggerPrintf;
+ fileLogger->base.flush = FileLoggerFlush;
+ fileLogger->base.destroy = FileLoggerDestroy;
+ fileLogger->fp = fp;
+
+ *logger = &fileLogger->base;
+ return ESR_SUCCESS;
+}
+
+/**
+ * Initializes the LOG library. This function must be called before any
+ * logging can take place.
+ *
+ * @param logger The logger to be used to output the messages. If NULL, then
+ * logging goes to PSTDERR. @param logLevel The level of logging requested.
+ *
+ * @return ESR_SUCCESS if success, anything else if an error occurs.
+ *
+ */
+ESR_ReturnCode PLogInit(PLogger *logger, unsigned int logLevel)
+{
+ ESR_ReturnCode rc = ESR_SUCCESS;
+
+ if (Glogger != NULL)
+ return ESR_INVALID_STATE;
+
+ GlogLevel = logLevel;
+
+#ifdef USE_THREAD
+ if ((rc = PtrdMutexCreate(&Gmutex)) != ESR_SUCCESS)
+ return rc;
+#endif
+
+ if (logger != NULL)
+ Glogger = logger;
+ else
+ {
+ rc = createPFileLogger(PSTDERR, &Glogger);
+ if (rc != ESR_SUCCESS)
+ goto CLEANUP;
+ }
+
+ return rc;
+CLEANUP:
+#ifdef USE_THREAD
+ if (Gmutex != NULL)
+ {
+ PtrdMutexDestroy(Gmutex);
+ Gmutex = NULL;
+ }
+#endif
+ return rc;
+}
+
+ESR_ReturnCode PLogIsInitialized(ESR_BOOL* isInit)
+{
+ if (isInit == NULL)
+ return ESR_INVALID_STATE;
+ *isInit = Glogger != NULL;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PLogIsLocked(ESR_BOOL* isLocked)
+{
+ if (isLocked == NULL)
+ return ESR_INVALID_STATE;
+ *isLocked = locked;
+ return ESR_SUCCESS;
+}
+
+/**
+ * Shutdowns the LOG library. Once this function is called, no logging activity can be performed.
+ * Also, the logger that was given to pLogInit is destroyed.
+ *
+ * @return ESR_SUCCESS if success, anything else if an error occurs.
+ *
+ */
+ESR_ReturnCode PLogShutdown()
+{
+ ESR_ReturnCode rc = ESR_SUCCESS;
+
+ if (Glogger == NULL)
+ return ESR_INVALID_STATE;
+
+#ifdef USE_THREAD
+ if ((rc = PtrdMutexDestroy(Gmutex)) != ESR_SUCCESS)
+ return rc;
+ Gmutex = NULL;
+#endif
+
+ if (Glogger->flush != NULL)
+ Glogger->flush(Glogger);
+ Glogger->destroy(Glogger);
+ Glogger = NULL;
+ return rc;
+}
+
+ESR_ReturnCode PLogGetLevel(unsigned int *logLevel)
+{
+ if (Glogger == NULL)
+ return ESR_INVALID_STATE;
+ if (logLevel == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ *logLevel = GlogLevel;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PLogSetLevel(unsigned int logLevel)
+{
+ if (Glogger == NULL)
+ return ESR_INVALID_STATE;
+
+ GlogLevel = logLevel;
+ return ESR_SUCCESS;
+}
+
+#define TIME_BUF_SIZE 24
+#define TIME_FORMAT L("%Y/%m/%d %H:%M:%S")
+#define PLOG_PANIC(x, rc) \
+ do \
+ { \
+ { \
+ pfprintf(PSTDERR, L("[%s:%d] %s failed with %s\n"), __FILE__, __LINE__, x, ESR_rc2str(rc)); \
+ pfflush(PSTDERR); \
+ } \
+ } while (0)
+
+static ESR_ReturnCode logIt(const LCHAR *format, va_list args, ESR_BOOL showStackTrace)
+{
+ ESR_ReturnCode rc = ESR_SUCCESS;
+ ESR_ReturnCode flushRC = ESR_SUCCESS;
+#ifdef USE_STACKTRACE
+#define BUFFER_SIZE P_MAX_STACKTRACE + 2000
+#else
+#define BUFFER_SIZE 2000
+#endif
+ LCHAR buffer[BUFFER_SIZE] = L("");
+
+ // TODO: Remove once logging subsystem supports "warn" level
+ if (strstr(format, "ESR_BUFFER_OVERFLOW")==format)
+ return ESR_SUCCESS;
+
+#ifdef USE_STACKTRACE
+ if (Glogger == NULL)
+ {
+ /*
+ * There are three possible scenerios for why logging would occur although the PLog module
+ * is uninitialized:
+ *
+ * 1) The code fails before PLog is initialized (perhaps in other portable components)
+ * 2) The user forgets to initialize the PLog module
+ * 3) The code fails after PLog is uninitialized (on shutdown)
+ *
+ * We do our best by logging any errors but this might result in the memory leak of
+ * the PStackTrace module in case 3.
+ */
+ rc = PStackTraceCreate();
+ if (rc != ESR_SUCCESS)
+ {
+ PLOG_PANIC(L("PStackTraceCreate"), rc);
+ goto CLEANUP;
+ }
+ }
+ else
+ {
+#ifdef USE_THREAD
+ rc = PtrdMutexLock(Gmutex);
+ if (rc != ESR_SUCCESS)
+ return rc;
+#endif
+ }
+ if (locked)
+ return ESR_INVALID_STATE;
+ locked = ESR_TRUE;
+
+ if (GlogFormat & LOG_OUTPUT_FORMAT_DATE_TIME)
+ {
+ PTimeStamp now;
+ struct tm* loctime;
+ LCHAR timeStr[TIME_BUF_SIZE];
+ size_t timeStrSize;
+
+ PTimeStampSet(&now);
+ loctime = localtime(&now.secs);
+ timeStrSize = LSTRFTIME(timeStr, TIME_BUF_SIZE, TIME_FORMAT, loctime);
+ passert(timeStrSize == (TIME_BUF_SIZE - 5));
+ psprintf(timeStr + (TIME_BUF_SIZE - 5), ".%03hu", now.msecs);
+
+ psprintf(buffer + LSTRLEN(buffer), L("%s|"), timeStr);
+ passert(LSTRLEN(buffer) < BUFFER_SIZE);
+ }
+
+ if (GlogFormat & LOG_OUTPUT_FORMAT_THREAD_ID)
+ {
+ rc = psprintf(buffer + LSTRLEN(buffer), L("trd=%u|"), PtrdGetCurrentThreadId());
+ passert(LSTRLEN(buffer) < BUFFER_SIZE);
+ }
+
+ if (GlogFormat & LOG_OUTPUT_FORMAT_MODULE_NAME && showStackTrace)
+ {
+ size_t len = P_MAX_STACKTRACE;
+ LCHAR text[P_MAX_STACKTRACE];
+ LCHAR* index;
+ size_t i;
+
+ rc = PStackTraceGetValue((LCHAR*) & text, &len);
+ if (rc == ESR_SUCCESS)
+ {
+ for (i = 0; i < 2; ++i)
+ {
+ rc = PStackTracePopLevel((LCHAR*) & text);
+ if (rc != ESR_SUCCESS)
+ {
+ PLOG_PANIC(L("PStackTracePopLevel"), rc);
+ goto CLEANUP;
+ }
+ }
+ index = text;
+ while (index)
+ {
+ index = LSTRSTR(index, L(" at\n"));
+ if (index != NULL)
+ {
+ *(index + 1) = L('<');
+ *(index + 2) = L('-');
+ *(index + 3) = L(' ');
+ }
+ }
+ }
+ else if (rc == ESR_NOT_SUPPORTED)
+ LSTRCPY(text, L(""));
+ else if (rc != ESR_SUCCESS)
+ {
+ PLOG_PANIC(L("PStackTraceGetValue"), rc);
+ goto CLEANUP;
+ }
+ rc = psprintf(buffer + LSTRLEN(buffer), L("Module=%s|"), text);
+ passert(LSTRLEN(buffer) < BUFFER_SIZE);
+ }
+
+ pvsprintf(buffer + LSTRLEN(buffer), format, args);
+#else
+ pvsprintf(buffer + LSTRLEN(buffer), format, args);
+#endif
+ passert(LSTRLEN(buffer) < BUFFER_SIZE);
+
+ psprintf(buffer + LSTRLEN(buffer), L("\n"));
+ passert(LSTRLEN(buffer) < BUFFER_SIZE);
+
+ if (Glogger != NULL)
+ {
+ rc = Glogger->printf(Glogger, L("%s"), buffer);
+ if (rc != ESR_SUCCESS)
+ goto CLEANUP;
+ flushRC = Glogger->flush(Glogger);
+ }
+ else
+ {
+ /* We need to log but the logging module is disabled or is locked so we output to stderr instead */
+ {
+ pfprintf(PSTDERR, L("%s"), buffer);
+ pfflush(PSTDERR);
+ }
+ }
+ locked = ESR_FALSE;
+#ifdef USE_THREAD
+ PtrdMutexUnlock(Gmutex);
+#endif
+ return flushRC;
+CLEANUP:
+ if (Glogger != NULL && Glogger->flush != NULL)
+ flushRC = Glogger->flush(Glogger);
+ locked = ESR_FALSE;
+#ifdef USE_THREAD
+ PtrdMutexUnlock(Gmutex);
+#endif
+ return rc != ESR_SUCCESS ? rc : flushRC;
+}
+
+/**
+ * Conditionally PLogs a message. The message is logged only if module is enabled.
+ *
+ * @param msg The message format specification (ala printf).
+ * @return ESR_SUCCESS if success, anything else if an error occurs.
+ */
+ESR_ReturnCode PLogMessage(const char* msg, ...)
+{
+ va_list args;
+ ESR_ReturnCode rc;
+#if USE_STACKTRACE
+ size_t depth;
+#endif
+
+#if defined (ANDROID)
+#if defined (HAVE_ANDROID_OS)
+ return ( ESR_SUCCESS );/* Get rid of this for phone device */
+#endif
+#endif
+
+ if (Glogger == NULL)
+ return ESR_INVALID_STATE;
+#ifdef USE_STACKTRACE
+ return ESR_SUCCESS;
+ rc = PStackTraceGetDepth(&depth);
+
+ if (rc == ESR_NOT_SUPPORTED)
+ {
+ /* Debugging symbols are missing */
+ return ESR_SUCCESS;
+ }
+ else if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, L("PStackTraceGetDepth"), ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+
+ /* Remove PLogMessage() from depth */
+ --depth;
+ if (GlogLevel < depth)
+ return ESR_SUCCESS;
+#endif
+
+ va_start(args, msg);
+ rc = logIt(msg, args, ESR_FALSE);
+ va_end(args);
+ return rc;
+#if USE_STACKTRACE
+CLEANUP:
+ return rc;
+#endif
+}
+
+
+/**
+ * Unconditionally logs an error message.
+ *
+ * @param msg The message format specification (ala printf).
+ * @return ESR_SUCCESS if success, anything else if an error occurs.
+ */
+ESR_ReturnCode PLogError(const char* msg, ...)
+{
+ va_list args;
+ ESR_ReturnCode rc;
+#if defined (ANDROID)
+#if defined (HAVE_ANDROID_OS)
+ char log_text [2048];
+#endif
+#endif
+
+ va_start(args, msg);
+#if defined (ANDROID)
+#if defined (HAVE_ANDROID_OS)
+ pvsprintf ( log_text, msg, args);
+/* We need to disable some error messages because they are frequently not
+ * errors but due to sloppy use of some functions. This prevents us from
+ * getting flooded with bad error messages. SteveR
+ */
+ if ( ( strncmp ( log_text, FILTER_MSG_1, FILTER_MSG_1_SIZE ) != 0 ) &&
+ ( strncmp ( log_text, FILTER_MSG_2, FILTER_MSG_2_SIZE ) != 0 ) )
+ {
+ LOGE ( log_text );
+ }
+ rc = 0;
+#else
+ rc = logIt(msg, args, ESR_TRUE);
+#endif
+#else
+ rc = logIt(msg, args, ESR_TRUE);
+#endif
+ va_end(args);
+
+ return rc;
+}
+
+
+
+ESR_ReturnCode PLogCreateFileLogger(PFile* file, PLogger **logger)
+{
+ if (logger == NULL || file == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ return createPFileLogger(file, logger);
+}
+
+/**
+ * Creates a logger that logs to a circular file.
+ *
+ * @param filename The name of the file to be created.
+ * @param maxsize The maximum number of bytes that the file may have.
+ * @param logger logger handle receiving the created logger.
+ */
+ESR_ReturnCode PLogCreateCircularFileLogger(const LCHAR *filename,
+ unsigned int maxsize,
+ PLogger **logger)
+{
+ return ESR_NOT_SUPPORTED;
+}
+
+
+ESR_ReturnCode PLogSetFormat(LOG_OUTPUT_FORMAT format)
+{
+ GlogFormat = format;
+ return ESR_SUCCESS;
+}
diff --git a/portable/src/pmalloc.c b/portable/src/pmalloc.c
new file mode 100644
index 0000000..eaf8007
--- /dev/null
+++ b/portable/src/pmalloc.c
@@ -0,0 +1,610 @@
+/*---------------------------------------------------------------------------*
+ * pmalloc.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+
+/* this source file is only used when PORTABLE_DINKUM_MEM_MGR is defined
+ */
+#ifdef PORTABLE_DINKUM_MEM_MGR
+
+#include <stdlib.h>
+#include <string.h> /* for memset */
+#include "pmalloc.h"
+#include "passert.h"
+#include "ptypes.h"
+#include "plog.h"
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /*
+ * There are two controlling options within this scheme:
+ *
+ * STATIC_MEMORY_POOL: When defined, there is a static array from which memory is
+ * allocated. The size of this array is defined at compile time. When undefined
+ * (the default), the memory is allocated via malloc(). This code works under PSOS and
+ * PSOSIM, but has not been tested anywhere else (4March02).
+ * VOYAGER_KERNEL_MEMORY: When defined for the Voyager platform, it is similar to the
+ * non-static memory pool, but the memory buffer is pre-defined, and is simply pointed
+ * at by the pmalloc initializer.
+ * RTXC_PARTITION_MEMORY: When defined for the RTXC operating system, uses a static kernel
+ * partition resource for the memory chunk.
+ * VOYAGER_KERNEL_MEMORY and RTXC_PARTITION_MEMORY are mutually exclusive and take precedence
+ * over STATIC_MEMORY.
+ *
+
+ * the standard off-the-shelf Dinkumware software is pretty slow, primarily due to
+ * scanning the free-memory linked list in PortFree(). If SPEEDUP is defined, then
+ * split the memory pool into imaginary 'bins', and keep track of the first free list
+ * entry in each bin. Then the linked list lookup can be MUCH faster, as you can
+ * start very close to the final destination in the linked list.
+ *
+ * (If SPEEDUP_COMPARE is defined, then run BOTH the standard technique and the
+ * speedup technique and compare the results.)
+ */
+
+ /* malloc function */
+ _STD_BEGIN
+
+ /* data *******************************************************************************/
+
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+ /* Verify that memory pool actually was created, because of the lack of structure, this is accessed externally */
+ ESR_ReturnCode memory_pool_creation_status = ESR_FATAL_ERROR;
+#endif
+
+ /* static data */
+ _Altab _Aldata = {0}; /* heap initially empty */
+ psize_t _Size_block = {SIZE_BLOCK}; /* preferred _Getmem chunk */
+
+ /* Memory pool size */
+#define MEM_SIZE_MB( mbytes ) ((mbytes) * 1024 * 1024 )
+
+#ifndef MEM_SIZE
+ /* If not defined on the command line, use default values. */
+#define MEM_SIZE MEM_SIZE_MB( 5 )
+#endif
+
+ /* Memory pool initialized */
+ static int pmallocInitted = FALSE; /* TRUE once initialized */
+
+#ifdef STATIC_MEMORY_POOL
+ /* The memory pool can either be statically allocated or require a one-time system malloc.
+ * For VTB, the system was taking 2 seconds to zero the static memBuffer[] array at
+ * boot time, since it's in the BSS segment. Therefore, for VTB, it is better to allocate
+ * at run time.
+ */
+ static char memBuffer[MEM_SIZE];
+#else
+ static char *memBuffer;
+#endif
+
+ static psize_t memSize = MEM_SIZE;
+
+ /* Memory pool free list */
+ /* partition memory range into 'bins', and keep track of the first
+ * free list entry in each bin. This is to speed up the linked-list search
+ * that takes place when memory is freed.
+ */
+#define BIN_BITS 14 /* smaller number ==> more bins */
+#define BIN_SIZE 16384 /* 2 ^ BIN_BITS */
+
+#define __NUM_MEM_BINS(memPoolSize) (((memPoolSize)/BIN_SIZE) + 5) /* 5 = extra for roundoff */
+#define GET_MEM_BIN( _ptr_ ) (int)(((unsigned int)_ptr_ - (unsigned int)&memBuffer[0]) >> BIN_BITS)
+
+#define NUM_MEM_BINS __NUM_MEM_BINS(MEM_SIZE)
+static _Cell *binsFirstFreeCell[NUM_MEM_BINS+1] = {0};
+ static psize_t numMemBins;
+
+ /* Memory Pool sbrk/getmem variables */
+
+ static char *__heap_ptr = NULL;
+ static char *__heap_end = NULL;
+ static int maxMemUsed = 0;
+
+ /* Memory Pool initialization and _GetMem functions ************************************/
+
+#if _USE_EXISTING_SYSTEM_NAMES
+#define _Sbrk sbrk
+#endif
+
+ _STD_BEGIN
+
+ void *_Sbrk(int incr)
+ {
+ char *ret;
+
+ /* Subtract 1 from __heap_ptr so that the left hand side of the comparison evaluates to the address of the
+ last address of the requested memory block */
+ if ((__heap_ptr + incr - 1) > __heap_end) return(void *) - 1;
+
+ ret = __heap_ptr;
+ __heap_ptr += incr;
+ maxMemUsed += incr;
+ return (void *)ret;
+ }
+
+ void *_Getmem(psize_t size)
+ { /* allocate raw storage */
+ void *p;
+ int isize = size;
+
+ return (isize <= 0 || (p = _Sbrk(isize)) == (void *) - 1
+ ? 0 : p);
+ }
+ _STD_END
+
+ /* PortMallocInit() : initialize memory pool. There is no initialization needed for
+ * a static memory pool. Otherwise, perform a one-time malloc from the OS.
+ */
+ void PortMallocInit(void)
+ {
+#if defined STATIC_MEMORY_POOL
+ memSize = MEM_SIZE;
+#else
+ /* TODO: is malloc of binsFirstFreeCell safe under PSOS in all conditions ? */
+ memBuffer = (char *)malloc(memSize);
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+ if (memBuffer != NULL) /* For external access, check comment at top */
+ memory_pool_creation_status = ESR_SUCCESS;
+#endif
+ numMemBins = __NUM_MEM_BINS(memSize);
+#endif /* #ifdef VOYAGER_KERNEL_MEMORY */
+
+ passert(memBuffer != NULL);
+ passert(binsFirstFreeCell != NULL);
+
+ __heap_ptr = &memBuffer[0];
+ __heap_end = &memBuffer[memSize-1];
+
+ /* set initted flag so we only do this once */
+ pmallocInitted = TRUE;
+ maxMemUsed = 0;
+
+ memset(&_Aldata, 0, sizeof(_Altab));
+
+ memset(binsFirstFreeCell, 0, sizeof(_Cell*)*(NUM_MEM_BINS + 1));
+ }
+
+ void PortMallocTerm(void)
+ {
+#ifndef STATIC_MEMORY_POOL
+ memSize = 0;
+ free(memBuffer);
+ memBuffer = NULL;
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+ memory_pool_creation_status = ESR_FATAL_ERROR; /* For external access, check comment at top */
+#endif
+#endif
+ pmallocInitted = FALSE;
+ }
+
+ /* PortGetMaxMemUsed() : return the maximum real memory allocated.
+ * There is another function of the same name in pmemory.cpp, for tracking
+ * psos block memory. It uses #ifdef MEM_PSOS_BLOCK_SCHEME to enable.
+ */
+ int PortMallocGetMaxMemUsed(void)
+ {
+ return maxMemUsed;
+ }
+
+ /* PortMallocSetPoolSize( psize_t size ) : define size of memory pool.
+ */
+ void PortMallocSetPoolSize(psize_t size)
+ {
+#if !defined(STATIC_MEMORY_POOL) && !defined(VOYAGER_KERNEL_MEMORY) && !defined(RTXC_PARTITION_MEMORY)
+ if (!pmallocInitted)
+ {
+ memSize = size;
+ }
+#else
+ (void)size;
+#endif
+ }
+
+ /* PortMallocGetPoolSize() : return size of memory pool.
+ */
+ psize_t PortMallocGetPoolSize(void)
+ {
+#if defined STATIC_MEMORY_POOL
+ return MEM_SIZE;
+#else
+ return memSize;
+#endif
+ }
+
+ /* debug *******************************************************************************/
+
+ /* xalloc.h internal header - debugging components */
+#if DEBUG
+
+ int _OK_Cell(_Cell *p)
+ {
+ passert(SIZE_CELL <= p->_Size);
+ return 1;
+ }
+
+ typedef struct _DB_Altab
+ {
+ psize_t total_heap;
+ psize_t total_alloc;
+ psize_t total_free;
+ }
+ _DB_Altab;
+
+ _DB_Altab _DB_Altab_object = {0};
+
+ void _UPD_Altab(psize_t d_heap, psize_t d_alloc, psize_t d_free)
+ {
+ _DB_Altab *pd = &_DB_Altab_object;
+ pd->total_heap += d_heap;
+ pd->total_alloc += d_alloc;
+ pd->total_free += d_free;
+ }
+
+ int _OK_Altab(_Altab *p)
+ {
+ _DB_Altab *pd = &_DB_Altab_object;
+ _Cell *q;
+ psize_t total_free = 0;
+ if (p->_Head == 0)
+ return 1;
+ for (q = p->_Head; q != 0; q = q->_Next)
+ {
+ total_free += q->_Size;
+ _OK_Cell(q);
+ if (q->_Next != 0)
+ {
+ passert(_PTR_NORM((char *)q + q->_Size) <=
+ _PTR_NORM((char *)q->_Next));
+ passert(_PTR_NORM(q) < _PTR_NORM(q->_Next));
+ }
+ }
+ passert(pd->total_heap == pd->total_alloc + pd->total_free);
+ passert(total_free == pd->total_free);
+ return 1;
+ }
+#endif /* DEBUG */
+
+ /* allocation functions ***************************************************************/
+
+ static _Cell **findmem(psize_t size)
+ { /* find storage */
+ _Cell *q, **qb;
+
+ for (; ;)
+ { /* check freed space first */
+ if ((qb = _Aldata._Plast) == 0)
+ { /* take it from the top */
+ for (qb = &_Aldata._Head; *qb != 0;
+ qb = &(*qb)->_Next)
+ if (size <= (*qb)->_Size)
+ return (qb);
+ }
+ else
+ { /* resume where we left off */
+ for (; *qb != 0; qb = &(*qb)->_Next)
+ if (size <= (*qb)->_Size)
+ return (qb);
+ q = *_Aldata._Plast;
+ for (qb = &_Aldata._Head; *qb != q;
+ qb = &(*qb)->_Next)
+ if (size <= (*qb)->_Size)
+ return (qb);
+ }
+ { /* try to buy more space */
+ psize_t bs;
+
+ for (bs = _Size_block; ; bs >>= 1)
+ { /* try larger blocks first */
+ if (bs < size)
+ bs = size;
+ if ((q = (_Cell *)_Getmem(bs)) != 0)
+ break;
+ else if (bs == size)
+ return (0); /* no storage */
+ }
+ /* got storage: add to heap and retry */
+ q->_Size = bs;
+ _UPD_Altab(q->_Size, q->_Size, 0); /* heap=alloc+free */
+ PortFree((char *)q + CELL_OFF);
+ }
+ }
+ }
+
+
+ void *(PortMalloc)(psize_t size_arg)
+ { /* allocate a data object on the heap */
+ _Cell *q, **qb;
+#ifdef SPEEDUP
+ int qbsBin;
+ int qbNextBin;
+#endif /* SPEEDUP */
+ psize_t size;
+
+ passert(pmallocInitted);
+
+ size = (size_arg + (CELL_OFF + M_MASK)) & ~M_MASK;
+
+ _OK_Altab(&_Aldata);
+ if (size <= size_arg)
+ return (0); /* size_arg too large */
+ if (size < SIZE_CELL) /* round up size */
+ size = SIZE_CELL;
+ if ((qb = findmem(size)) == 0)
+ return (0);
+ q = *qb;
+ if (q->_Size - SIZE_CELL < size)
+ {
+ /* use entire cell (there's not enough space to carve out a new cell from this one) */
+#ifdef SPEEDUP
+ /* remove *qb cell from free list.
+ * careful : the Next pointer may be in a different bin.
+ */
+ qbsBin = GET_MEM_BIN(*qb);
+
+ /* Check whether the cell is at the end of the 'free' linked-list */
+ if (0 != ((*qb)->_Next))
+ {
+ /* The cell is not at the end of the free linked-list; find out which bin the next free cell is in */
+ qbNextBin = GET_MEM_BIN((*qb)->_Next);
+
+ if (qbsBin == qbNextBin)
+ {
+ if (binsFirstFreeCell[qbsBin] == *qb)
+ {
+ /* The allocated cell was the first free cell in the bin; update the first free cell
+ pointer to point to the next free cell */
+ binsFirstFreeCell[qbsBin] = (*qb)->_Next;
+ }
+ }
+ else
+ {
+ if (binsFirstFreeCell[qbsBin] == *qb)
+ {
+ /* The allocated cell was the only free cell in the bin; update the first free cell
+ pointer to point to NULL */
+
+ binsFirstFreeCell[qbsBin] = 0;
+ }
+ }
+ }
+ else
+ {
+ /* Cell is at the end of the 'free' linked-list */
+ if (binsFirstFreeCell[qbsBin] == *qb)
+ {
+ /* The allocated cell was the first free cell in the bin; there are no following free cells
+ so set the first free cell pointer to NULL */
+ binsFirstFreeCell[qbsBin] = 0;
+ }
+ }
+#endif /* SPEEDUP */
+ *qb = q->_Next;
+ }
+ else
+ { /* peel off a residual cell */
+ *qb = (_Cell *)((char *)q + size);
+ (*qb)->_Next = q->_Next;
+ (*qb)->_Size = q->_Size - size;
+ q->_Size = size;
+#ifdef SPEEDUP
+ /* remove q from free list, and add *qb to free list.
+ * Do this as two separate steps because they may be in 2 different bins.
+ */
+ /* remove q from free list */
+ if (binsFirstFreeCell[GET_MEM_BIN(q)] == q)
+ binsFirstFreeCell[GET_MEM_BIN(q)] = 0;
+ /* now add *qb to its bin's free list if it's the first */
+ qbsBin = GET_MEM_BIN(*qb);
+ if ((binsFirstFreeCell[qbsBin] == 0) || (*qb < binsFirstFreeCell[qbsBin]))
+ binsFirstFreeCell[qbsBin] = *qb;
+#endif /* SPEEDUP */
+ }
+ _Aldata._Plast = qb; /* resume scan here */
+ _UPD_Altab(0, q->_Size, -q->_Size); /* heap=alloc+free */
+ _OK_Altab(&_Aldata);
+ return ((char *)q + CELL_OFF);
+ }
+ _STD_END
+
+
+ /* free function */
+ _STD_BEGIN
+
+ void(PortFree)(void *ptr)
+ { /* free an allocated data object */
+ register _Cell *q;
+ register psize_t size;
+#ifdef SPEEDUP
+ int binNum;
+ int binIndex;
+ int qNextBin;
+ int qNextNextBin;
+#endif /* SPEEDUP */
+ static int portFreeCount = 0;
+ portFreeCount++;
+
+ passert(pmallocInitted);
+
+ _OK_Altab(&_Aldata);
+ if (ptr == 0)
+ return;
+ q = (_Cell *)((char *)ptr - CELL_OFF);
+ size = q->_Size;
+#ifdef SPEEDUP
+ binNum = GET_MEM_BIN(q);
+#endif /* SPEEDUP */
+ if (size < SIZE_CELL || (size & M_MASK) != 0)
+ return; /* erroneous call, bad count */
+ if (_Aldata._Head == 0
+ || _PTR_NORM(q) < _PTR_NORM(_Aldata._Head))
+ { /* insert at head of list */
+ q->_Next = _Aldata._Head;
+ _Aldata._Head = q;
+#ifdef SPEEDUP
+ /* always the start of a bin */
+ binsFirstFreeCell[binNum] = q;
+#endif /* SPEEDUP */
+ }
+ else
+ { /* scan for insertion point */
+ register _Cell *qp = _Aldata._Head;
+ register char *qpp;
+ register _Cell *nextCell;
+#if !defined SPEEDUP || defined SPEEDUP_COMPARE
+ _Cell *savedQp;
+
+ /* this search loop is where all the time is spent */
+ while ((nextCell = qp->_Next) != 0
+ && _PTR_NORM(nextCell) < _PTR_NORM(q))
+ qp = qp->_Next;
+ savedQp = qp;
+#endif /* SPEEDUP */
+
+#ifdef SPEEDUP
+ /* this is where the SPEEDUP code is sped up : start with the bin's first free cell */
+ _Cell *firstFreeInBin = binsFirstFreeCell[binNum];
+ if ((firstFreeInBin != 0) && (q > firstFreeInBin))
+ {
+ qp = firstFreeInBin;
+ while ((nextCell = qp->_Next) != 0
+ && _PTR_NORM(nextCell) < _PTR_NORM(q))
+ {
+ qp = qp->_Next;
+ }
+ }
+ else
+ {
+ /* go back to the previous non-zero bin */
+ qp = NULL; /* for diagnostics */
+ for (binIndex = binNum; binIndex >= 0; binIndex--)
+ {
+ if ((binsFirstFreeCell[binIndex] != 0) && (q > binsFirstFreeCell[binIndex]))
+ {
+ qp = binsFirstFreeCell[binIndex];
+ break;
+ }
+ }
+ /* this code for diagnostic purposes to see how often it happens. otherwise,
+ * qp could have been set to _Aldata._Head prior to the binIndex loop above.
+ */
+ if (qp == NULL)
+ {
+ qp = _Aldata._Head;
+ }
+
+ /* find the free cell location */
+ while ((nextCell = qp->_Next) != 0
+ && _PTR_NORM(nextCell) < _PTR_NORM(q))
+ qp = qp->_Next;
+ }
+
+#ifdef SPEEDUP_COMPARE
+ if (qp != savedQp)
+ printf("oops \n");
+#endif /* SPEEDUP_COMPARE */
+#endif /* SPEEDUP */
+
+#if !defined SPEEDUP || defined SPEEDUP_COMPARE
+ qp = savedQp;
+#endif /* SPEEDUP */
+
+ qpp = (char *)qp + qp->_Size;
+ if (_PTR_NORM((char *)q) < _PTR_NORM(qpp))
+ return; /* erroneous call, overlaps qp */
+ else if (_PTR_NORM(qpp) == _PTR_NORM((char *)q))
+ { /* merge qp and q (merge with prior cell) */
+ /* nothing to do to bin's free list here */
+ qp->_Size += q->_Size;
+ q = qp;
+ }
+ else if (qp->_Next != 0 && _PTR_NORM((char *)qp->_Next)
+ < _PTR_NORM((char *)q + q->_Size))
+ return; /* erroneous call, overlaps qp->_Next */
+ else
+ { /* splice q after qp */
+#ifdef SPEEDUP
+ /* add 1 entry here - this could change first entry in q's bin */
+ _Cell *firstFree = binsFirstFreeCell[binNum];
+ if ((firstFree == 0) || (q < firstFree))
+ binsFirstFreeCell[binNum] = q;
+#endif /* SPEEDUP */
+ q->_Next = qp->_Next;
+ qp->_Next = q;
+ }
+ }
+ if (q->_Next != 0 && _PTR_NORM((char *)q + q->_Size)
+ == _PTR_NORM((char *)q->_Next))
+ { /* merge q and q->_Next (merge with latter cell) */
+#ifdef SPEEDUP
+ /* lose 1 cell here - this could change first entry in bin.
+ * if q->_Next was first in bin, now it's its Next.
+ * careful : watch for next being in a different bin.
+ */
+ qNextBin = GET_MEM_BIN(q->_Next);
+
+ if (binsFirstFreeCell[qNextBin] == q->_Next)
+ {
+ /* The q->_Next cell is the first free cell in its bin; set the first free cell
+ pointer to NULL for now; if there is another free cell in the same bin then
+ the first free cell pointer will be updated in next 'if' code block */
+ binsFirstFreeCell[qNextBin] = 0;
+
+ /* If there is another free cell after q->_Next and it's in the same bin then
+ update the first free cell pointer if necessary */
+ if (0 != (q->_Next->_Next))
+ {
+ qNextNextBin = GET_MEM_BIN(q->_Next->_Next);
+
+ /* The first free cell pointer for q->_Next->_Next's bin can only be set to 0
+ by the code above; if it is 0 then q->_Next->_Next must be the first free
+ cell in the bin */
+ if (0 == binsFirstFreeCell[qNextNextBin])
+ {
+ binsFirstFreeCell[qNextNextBin] = q->_Next->_Next;
+ }
+ }
+ }
+#endif /* SPEEDUP */
+ _Aldata._Plast = 0; /* deoptimize for safety */
+ q->_Size += q->_Next->_Size;
+ q->_Next = q->_Next->_Next;
+ }
+ _UPD_Altab(0, -size, size); /* heap=alloc+free */
+ _OK_Altab(&_Aldata);
+ /* every successful free "falls off" here */
+ }
+ _STD_END
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* PORTABLE_DINKUM_MEM_MGR */
+
+
diff --git a/portable/src/pmemblock.c b/portable/src/pmemblock.c
new file mode 100644
index 0000000..5f3277d
--- /dev/null
+++ b/portable/src/pmemblock.c
@@ -0,0 +1,544 @@
+/*---------------------------------------------------------------------------*
+ * pmemblock.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#include "pmemory.h"
+#include "ptypes.h"
+
+#if PORTABLE_MEM_MGR == PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR
+
+#ifdef PSOSIM
+#define PSOS
+#endif
+
+#ifdef PSOS
+#include <stdlib.h>
+#include <psos.h>
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /* Data *****************************************************************/
+
+#define NUM_POOL_BINS 32
+#define NUM_POOL_SLOTS 8
+
+ typedef struct memory_pools
+ {
+ uint32 currentNumberOfPools;
+
+ struct pool_info
+ {
+ unsigned long poolId;
+ void* pMemory;
+ unsigned long size;
+ }
+ poolInfo[NUM_POOL_SLOTS];
+
+ }
+ MEMORY_POOL;
+
+ static MEMORY_POOL memoryPool[NUM_POOL_BINS];
+
+#define NUM_TRACKING_BINS NUM_POOL_BINS
+
+ /* Object tracking variables */
+ static struct tracking_struct
+ {
+ uint32 sCurrentAllocationSize;
+ uint32 sMaximumAllocationSize;
+ uint32 sTotalAllocationSize;
+
+ uint32 sCurrentAllocRealSize;
+ uint32 sMaximumAllocRealSize;
+ uint32 sTotalAllocRealSize;
+
+ uint32 sCurrentAllocationNumber;
+ uint32 sMaximumAllocationNumber;
+ uint32 sTotalAllocationNumber;
+
+ uint32 sCurrentAllocationNumberArray[NUM_TRACKING_BINS];
+ uint32 sMaximumAllocationNumberArray[NUM_TRACKING_BINS];
+ uint32 sTotalAllocationNumberArray[NUM_TRACKING_BINS];
+
+ uint32 sCurrentAllocationSizeArray[NUM_TRACKING_BINS];
+ uint32 sMaximumAllocationSizeArray[NUM_TRACKING_BINS];
+ uint32 sTotalAllocationSizeArray[NUM_TRACKING_BINS];
+ }
+ gMemoryTracking;
+
+
+ /* Functions *********************************************************/
+
+ static uint32 findBin(size_t size)
+ {
+ int i, bin;
+ for (i = 0, bin = 1; i < NUM_TRACKING_BINS; i++, bin <<= 1)
+ {
+ if ((int)size <= bin)
+ return i;
+ }
+
+ return 0;
+ }
+
+
+ static void MemoryTrackingInit(void)
+ {
+ int i;
+ /* Initialization of object tracking variables */
+ gMemoryTracking.sCurrentAllocationSize = 0;
+ gMemoryTracking.sMaximumAllocationSize = 0;
+ gMemoryTracking.sTotalAllocationSize = 0;
+
+ gMemoryTracking.sCurrentAllocationNumber = 0;
+ gMemoryTracking.sMaximumAllocationNumber = 0;
+ gMemoryTracking.sTotalAllocationNumber = 0;
+
+ gMemoryTracking.sCurrentAllocRealSize = 0;
+ gMemoryTracking.sMaximumAllocRealSize = 0;
+ gMemoryTracking.sTotalAllocRealSize = 0;
+
+ for (i = 0; i < NUM_TRACKING_BINS; i++)
+ {
+ gMemoryTracking.sCurrentAllocationNumberArray[i] = 0;
+ gMemoryTracking.sMaximumAllocationNumberArray[i] = 0;
+ gMemoryTracking.sTotalAllocationNumberArray[i] = 0;
+
+ gMemoryTracking.sCurrentAllocationSizeArray[i] = 0;
+ gMemoryTracking.sMaximumAllocationSizeArray[i] = 0;
+ gMemoryTracking.sTotalAllocationSizeArray[i] = 0;
+ }
+ }
+
+
+ static void MemoryTrackingAdd(size_t size)
+ {
+ /* Memory tracking code */
+ uint32 bin = findBin(size);
+ uint32 binsize = 1 << bin;
+ uint32 dummy;
+
+ /* for breakpoint setting */
+#ifdef PSOSIM
+ if (bin == 0)
+ dummy = 0;
+ if (bin == 1)
+ dummy = 0;
+ if (bin == 2)
+ dummy = 0;
+ if (bin == 3)
+ dummy = 0;
+ if (bin == 4)
+ dummy = 0;
+ if (bin == 5)
+ dummy = 0;
+ if (bin == 6)
+ dummy = 0;
+ if (bin == 7)
+ dummy = 0;
+ if (bin == 8)
+ dummy = 0;
+ if (bin == 9)
+ dummy = 0;
+ if (bin == 10)
+ dummy = 0;
+ if (bin == 11)
+ dummy = 0;
+ if (bin == 12)
+ dummy = 0;
+ if (bin == 13)
+ dummy = 0;
+ if (bin == 14)
+ dummy = 0;
+ if (bin == 15)
+ dummy = 0;
+ if (bin == 16)
+ dummy = 0;
+ if (bin == 17)
+ dummy = 0;
+ if (bin == 18)
+ dummy = 0;
+ if (bin == 19)
+ dummy = 0;
+ if (bin == 20)
+ dummy = 0;
+ if (bin == 21)
+ dummy = 0;
+ if (bin > 21)
+ dummy = 0;
+#endif /* PSOSIM */
+
+ gMemoryTracking.sCurrentAllocationSize += size;
+ gMemoryTracking.sTotalAllocationSize += size;
+ if (gMemoryTracking.sCurrentAllocationSize > gMemoryTracking.sMaximumAllocationSize)
+ gMemoryTracking.sMaximumAllocationSize = gMemoryTracking.sCurrentAllocationSize;
+
+ gMemoryTracking.sCurrentAllocRealSize += binsize;
+ gMemoryTracking.sTotalAllocRealSize += binsize;
+ if (gMemoryTracking.sCurrentAllocRealSize > gMemoryTracking.sMaximumAllocRealSize)
+ gMemoryTracking.sMaximumAllocRealSize = gMemoryTracking.sCurrentAllocRealSize;
+
+ gMemoryTracking.sCurrentAllocationNumber++;
+ gMemoryTracking.sTotalAllocationNumber++;
+ if (gMemoryTracking.sCurrentAllocationNumber > gMemoryTracking.sMaximumAllocationNumber)
+ gMemoryTracking.sMaximumAllocationNumber = gMemoryTracking.sCurrentAllocationNumber;
+
+ gMemoryTracking.sCurrentAllocationSizeArray[bin] += size;
+ gMemoryTracking.sTotalAllocationSizeArray[bin] += size;
+ if (gMemoryTracking.sCurrentAllocationSizeArray[bin] > gMemoryTracking.sMaximumAllocationSizeArray[bin])
+ gMemoryTracking.sMaximumAllocationSizeArray[bin] = gMemoryTracking.sCurrentAllocationSizeArray[bin];
+
+ gMemoryTracking.sCurrentAllocationNumberArray[bin]++;
+ gMemoryTracking.sTotalAllocationNumberArray[bin]++;
+ if (gMemoryTracking.sCurrentAllocationNumberArray[bin] > gMemoryTracking.sMaximumAllocationNumberArray[bin])
+ gMemoryTracking.sMaximumAllocationNumberArray[bin] = gMemoryTracking.sCurrentAllocationNumberArray[bin];
+ }
+
+
+ static void MemoryTrackingDelete(unsigned long size)
+ {
+ /* Memory tracking code */
+ uint32 bin = findBin(size);
+ uint32 binsize = 1 << bin;
+
+ gMemoryTracking.sCurrentAllocationSize -= size;
+ gMemoryTracking.sCurrentAllocationNumber--;
+
+ gMemoryTracking.sCurrentAllocationSizeArray[bin] -= size;
+ gMemoryTracking.sCurrentAllocationNumberArray[bin]--;
+
+ gMemoryTracking.sCurrentAllocRealSize -= binsize;
+ }
+
+
+ static void InitPools(void)
+ {
+ int i, j;
+ for (i = 0; i < NUM_POOL_BINS; i++)
+ {
+ memoryPool[i].currentNumberOfPools = 0;
+
+ for (j = 0; j < NUM_POOL_SLOTS; j++)
+ {
+ memoryPool[i].poolInfo[j].poolId = 0;
+ memoryPool[i].poolInfo[j].pMemory = NULL;
+ memoryPool[i].poolInfo[j].size = 0;
+ }
+ }
+ }
+
+
+ static void TermPools(void)
+ {
+ int i, j;
+ /* For some reason, deleting the region then freeing the memory causes a failure */
+ /* TODO: Figure out why??? */
+ for (i = 1; i < NUM_POOL_BINS; i++)
+ {
+ for (j = 0; j < (int)memoryPool[i].currentNumberOfPools; j++)
+ {
+ if (memoryPool[i].poolInfo[j].pMemory != NULL)
+ {
+ unsigned long retval = pt_delete(memoryPool[i].poolInfo[j].poolId);
+ PORT_ASSERT(retval == 0);
+
+ PORT_ASSERT_GOOD_WRITE_POINTER(memoryPool[i].poolInfo[j].pMemory);
+ free(memoryPool[i].poolInfo[j].pMemory);
+
+ memoryPool[i].poolInfo[j].poolId = 0;
+ memoryPool[i].poolInfo[j].pMemory = NULL;
+ memoryPool[i].poolInfo[j].size = 0;
+ }
+ }
+
+ memoryPool[i].currentNumberOfPools = 0;
+ }
+ }
+
+
+#define PARTITION_CONTROL_BLOCK_SIZE 0x400
+
+ static BOOL CreatePool(uint32 whichPool, uint32 poolSize)
+ {
+ static uint32 poolNumber = 0;
+
+ void* pMemory = NULL;
+ unsigned long poolId, unused;
+
+ uint32 currentNumberOfPools = memoryPool[whichPool].currentNumberOfPools;
+
+ PORT_ASSERT((whichPool >= 0) && (whichPool < NUM_POOL_BINS));
+
+ if (currentNumberOfPools == NUM_POOL_SLOTS)
+ return FALSE;
+
+
+ if (whichPool < 2)
+ {
+ /* Invalid partition size */
+ return FALSE;
+ }
+ else
+ {
+ char name[5];
+ unsigned long retval;
+
+ pMemory = malloc(poolSize * (1 << whichPool) + PARTITION_CONTROL_BLOCK_SIZE);
+ PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
+
+ /* No memory protection */
+ if (pMemory == NULL)
+ {
+ /* No memory left in system */
+ return FALSE;
+ }
+
+
+ sprintf(name, "DP%02d", poolNumber);
+
+ retval = pt_create(name, pMemory, 0, poolSize * (1 << whichPool) + PARTITION_CONTROL_BLOCK_SIZE,
+ 1 << whichPool, PT_LOCAL | PT_DEL, &poolId, &unused);
+ if (retval != 0)
+ {
+ /* Unable to create a pSOS partition */
+ return FALSE;
+ }
+ }
+
+ memoryPool[whichPool].poolInfo[currentNumberOfPools].poolId = poolId;
+ memoryPool[whichPool].poolInfo[currentNumberOfPools].pMemory = pMemory;
+ memoryPool[whichPool].poolInfo[currentNumberOfPools].size = poolSize;
+ memoryPool[whichPool].currentNumberOfPools++;
+
+ poolNumber++;
+
+ return TRUE;
+ }
+
+ static BOOL AddPool(uint32 whichPool, uint32 poolSize)
+ {
+ if (memoryPool[whichPool].poolInfo[0].pMemory == NULL)
+ return FALSE;
+
+ return CreatePool(whichPool, poolSize);
+ }
+
+ static void* AllocateFromPsos(uint32 whichPool, uint32 poolIndex, uint32 size)
+ {
+ uint32 retval;
+ void* pMemory;
+
+ PORT_ASSERT(memoryPool[whichPool].poolInfo[poolIndex].poolId);
+
+ retval = pt_getbuf(memoryPool[whichPool].poolInfo[poolIndex].poolId, &pMemory);
+
+ /* If we got memory, then return */
+ if (retval == 0)
+ {
+ PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
+ *((unsigned long *)pMemory) = (whichPool << 27) + (poolIndex << 24) + size;
+ return (unsigned long *)pMemory + 1;
+ }
+ else
+ return NULL;
+ }
+
+ static void* SearchPoolsForMemory(uint32 whichPool, uint32 size)
+ {
+ void* pMemory;
+ uint32 poolIndex;
+ /* Get memory from main region */
+ if (whichPool == 0)
+ {
+ pMemory = malloc(size);
+
+ /* No memory protection */
+ if (pMemory == NULL)
+ {
+ /* No memory left in system */
+ return NULL;
+ }
+
+ PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
+ *((unsigned long *)pMemory) = (whichPool << 27) + size;
+ return (unsigned long *)pMemory + 1;
+ }
+
+ /* Allocate memory from the first available bin (partition) */
+ for (poolIndex = 0; poolIndex < memoryPool[whichPool].currentNumberOfPools; poolIndex++)
+ {
+ pMemory = AllocateFromPsos(whichPool, poolIndex, size);
+ if (pMemory != NULL)
+ return pMemory;
+ }
+
+ /* Made it here because we ran out of memory in the pool, so try to add more pools */
+ if (AddPool(whichPool, memoryPool[whichPool].poolInfo[0].size >> 1) == FALSE)
+ {
+ /* All pools of this size have been consumed */
+ return NULL;
+ }
+
+ /* Allocate memory from newly created pool */
+ pMemory = AllocateFromPsos(whichPool, memoryPool[whichPool].currentNumberOfPools - 1, size);
+ if (pMemory != NULL)
+ return pMemory;
+
+ /* If we can't allocate from the newly created pool, then we have problems */
+ /* No memory protection */
+
+ /* No memory left in system */
+ return NULL;
+ }
+
+ void* PortMemBlockAllocateFromPool(uint32 size)
+ {
+ void* pMemory = NULL;
+ int poolIndex;
+ BOOL foundPool = FALSE;
+ uint32 whichPool;
+
+ PORT_ASSERT((size & 0xff000000) == 0);
+
+ size += 4;
+ whichPool = findBin(size); /* Add 4 so I can store info with data */
+ MemoryTrackingAdd(size);
+
+ /* If pool exists for the size needed, then use it, else find next largest pool */
+ for (poolIndex = whichPool; poolIndex < 32; poolIndex++)
+ if (memoryPool[poolIndex].poolInfo[0].pMemory != NULL)
+ {
+ foundPool = TRUE;
+ whichPool = poolIndex;
+ break;
+ }
+
+ /* If next largest pool doesn't exist, then use pool 0 (regions) */
+ if (!foundPool)
+ whichPool = 0;
+
+ /* Allocate memory from the first available bin */
+ pMemory = SearchPoolsForMemory(whichPool, size);
+ PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
+ return pMemory;
+ }
+
+ void PortMemBlockDeleteFromPool(void* pMemory)
+ {
+ unsigned long *pRealMemory = (unsigned long *)pMemory - 1;
+
+ uint32 whichPool = (*pRealMemory >> 27) & 0x0000001f;
+ uint32 whichBin = (*pRealMemory >> 24) & 0x00000007;
+
+ PORT_ASSERT_GOOD_WRITE_POINTER(pMemory);
+ MemoryTrackingDelete(*pRealMemory & 0x00ffffff);
+
+
+ if (whichPool == 0)
+ {
+ free(pRealMemory);
+ }
+ else
+ {
+ uint32 retval = pt_retbuf(memoryPool[whichPool].poolInfo[whichBin].poolId, pRealMemory);
+ PORT_ASSERT(retval == 0);
+ }
+ }
+
+ /* PortMemGetPoolSize() : return size of portable memory pool, or 0 if
+ * unknown.
+ */
+ int PortMemBlockGetPoolSize(void)
+ {
+ return 0; /* TODO: Find size of pool: 4Mar02 */
+ }
+
+ /* PortMemBlockSetPoolSize() : set size of portable memory pool on PSOS.
+ * This must be called before PortMemoryInit(), which is called by PortInit().
+ */
+ void PortMemBlockSetPoolSize(size_t sizeInBytes)
+ {}
+
+ int PortMemBlockInit(void)
+ {
+ InitPools();
+ CreatePool(findBin(1 << 3), 3000);
+ CreatePool(findBin(1 << 4), 10000);
+ CreatePool(findBin(1 << 5), 8000);
+ CreatePool(findBin(1 << 6), 16000);
+ CreatePool(findBin(1 << 7), 5000);
+ CreatePool(findBin(1 << 8), 1000);
+ CreatePool(findBin(1 << 9), 2000);
+ CreatePool(findBin(1 << 10), 50);
+ CreatePool(findBin(1 << 11), 20);
+ CreatePool(findBin(1 << 12), 24);
+ CreatePool(findBin(1 << 13), 16);
+ CreatePool(findBin(1 << 14), 10);
+ CreatePool(findBin(1 << 15), 16);
+ CreatePool(findBin(1 << 16), 4);
+ CreatePool(findBin(1 << 18), 6);
+
+ MemoryTrackingInit();
+ }
+
+ void PortMemBlockTerm(void)
+ {
+ TermPools();
+ }
+
+ void PortMemBlockTrackDump(void)
+ {
+ int i;
+
+ printf("\nCurrent Memory Usage = %d\nMaximum Memory Usage = %d\nTotal Memory Allocation = %d\n\n",
+ gMemoryTracking.sCurrentAllocationSize, gMemoryTracking.sMaximumAllocationSize, gMemoryTracking.sTotalAllocationSize);
+
+ printf("\nCurrent Real Memory Usage = %d\nMaximum Real Memory Usage = %d\nTotal Real Memory Allocation = %d\n\n",
+ gMemoryTracking.sCurrentAllocRealSize, gMemoryTracking.sMaximumAllocRealSize, gMemoryTracking.sTotalAllocRealSize);
+
+ for (i = 0; i < NUM_TRACKING_BINS; i++)
+ printf("Max size of 2^%2d byte objects = %d\n", i, gMemoryTracking.sMaximumAllocationSizeArray[i]);
+
+ printf("\nCurrent Memory Objects = %d\nMaximum Memory Objects = %d\nTotal Memory Objects = %d\n\n",
+ gMemoryTracking.sCurrentAllocationNumber, gMemoryTracking.sMaximumAllocationNumber, gMemoryTracking.sTotalAllocationNumber);
+
+ for (i = 0; i < NUM_TRACKING_BINS; i++)
+ printf("Max number for 2^%2d byte objects = %d\n", i, gMemoryTracking.sMaximumAllocationNumberArray[i]);
+ }
+
+ /* PortMemBlockGetMaxMemUsed() : return the maximum real memory allocated.
+ * There is another function of the same name in pmalloc.c, for tracking
+ * non-psos block memory.
+ */
+ int PortMemBlockGetMaxMemUsed(void)
+ {
+ return gMemoryTracking.sMaximumAllocRealSize;
+ }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PORTABLE_MEM_MGR == PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR */
+
diff --git a/portable/src/pmemfixed.c b/portable/src/pmemfixed.c
new file mode 100644
index 0000000..4d16ac1
--- /dev/null
+++ b/portable/src/pmemfixed.c
@@ -0,0 +1,705 @@
+/*---------------------------------------------------------------------------*
+ * pmemfixed.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#include "pmemory.h"
+#include "plog.h"
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+
+#ifdef PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME
+
+/*
+ How does the Fixed Size Memory Block Manager Work?
+ The memory manager manages an unlimited number of pools, each containing a linked list
+ of free memory blocks of a fixed size. The memory pools are ordered in increasing block
+ size, eg. pool # 0 contains 4 byte memory blocks, pool # 1 contains 8, etc. Each memory
+ block consists of a header and body. The header (which is currently 8 bytes long) is used
+ to store the address of the next free memory block in the linked list, and to store the
+ memory block's pool ID (this is used by the free function to determine which pool the block
+ originated from). The body is simply the usable memory. Whenever the application requests
+ memory of a given size, the memory manager selects the appropriate memory pool which contain
+ blocks large enough to satisfy the request. The memory manager removes a block from the
+ linked list and returns the address of the memory block body. If there are no blocks
+ available in the pool, then more blocks are created (if there is memory available); the
+ number created is configurable. If it is not possible to create more blocks, then the
+ memory manager searches the remaining pools in the sequence until it finds a free block or
+ it runs out of pools (in this case it will return a null pointer to the calling code).
+
+ How is the memory space allocated to the fixed block pools?
+ At start-up the memory manager requests one large memory block from the system (the size is
+ defined by #define MEM_SIZE). This memory is used to a) create the fixed size memory pools
+ (each contain the initial number defined in the code) and b) to create extra memory blocks
+ each time a particular pool has been exhausted (the number created is configurable for each
+ memory pool also). Once all of this memory has been used up it is also possible to make
+ further requests to the system for more memory (to create more fixed memory blocks); this
+ feature is switched on using the compilation flag ALLOW_ADDITIONAL_SYS_MEM_ALLOCS. Note
+ that once memory blocks have been added to a memory pool they cannot be removed and reused
+ in another, eg a 0.5 MByte memory block could not be removed from its 0.5 Mbyte pool in
+ order to create smaller 4 byte blocks in the 4byte block pool.
+
+ How is the large memory block from the system allocated?
+ It can be allocated in one of three ways depending on compile time definitions. If you define
+ STATIC_MEMORY_POOL, it's allocated as a static array. If you define RTXC_PARTITION_MEMORY,
+ it's allocated from the HEAP_MAP memory partition. If you don't define anything, it's allocated
+ using the system malloc call. Of course, RTXC_PARTITION should only be defined on when you building
+ for the RTXC operating system.
+
+ If STATIC_MEMORY_POOL or RTXC_PARTITION is defined, you cannot define ALLOW_ADDITIONAL_SYS_MEM_ALLOCS.
+
+ Key Points:
+ 1. Configurable memory block sizes (not restricted to power of 2 sizes).
+ 2. Best fit algorith.
+ 3. Dynamically increases the pool sizes (from an initial number).
+ 4. Can limit the total heap size.
+ 5. Configurable initial pool sizes.
+ 6. Allow additional system memory allocations in order to increase the pool sizes when the
+ 'heap' limit has been reached.
+ 7. Doesn't support block consolidation, and reuse across pools.
+
+*/
+
+/*************************** Header Files *************************************/
+
+#ifdef RTXC_PARTITION_MEMORY
+#include <rtxcapi.h>
+/* TODO - When rtxcgen is run, it will create this header file that should contain
+ * identifiers for various memory partitions that we will be using. For now, in order
+ * to get a compile, define a partition identifier.
+ */
+#define HEAP_MAP 1
+
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+
+ /*************************** Macros Definitions *******************************/
+ /* All of these should be defined on the command line
+ * #define MEM_MGR_STATS
+ * #define ALLOW_ADDITIONAL_SYS_MEM_ALLOCS
+ * #define ALLOW_POOL_GROWTHS
+ * #define MEM_SIZE
+ */
+
+ /*
+ #if (defined(STATIC_MEMORY_POOL) || defined(RTXC_PARTITION_MEMORY)) && defined(ALLOW_ADDITIONAL_SYS_MEM_ALLOCS)
+ #error Can't allocate additional memory blocks from the system.
+ #endif
+ */
+ /* TODO: Need to figure out a good size for this. */
+ /* This had better be the same as the block in HEAP_MAP as defined when building RTXC. */
+
+#ifndef MEM_SIZE
+ /* If not defined on the command line, use a default value of 10 megabytes for the heap. */
+#define MEM_SIZE (10 * 1024 * 1024) /* 10 MBytes */
+#endif
+
+#define MEM_BLOCK_HDR 8 /* (bytes): 16 bit Pool ID, 16 bit signature, 32 bit next block pointer */
+#define MEM_POOL_ID_OFFSET 0
+#define NEXT_BLOCK_PTR_OFFSET 1 /* (no. of 4 byte words) */
+#define MEM_BLOCK_HDR_OFFSET 2 /* (no. of 4 byte words) */
+
+#define MEM_POOL_ID_MASK 0x000000FF
+#define MEM_REQ_SIZE_MASK 0xFFFFFF00
+#define MEM_REQ_SIZE_BIT_SHIFT 8
+
+
+
+ /*************************** Type Defs ****************************************/
+
+ typedef struct
+ {
+ unsigned int accReqSize;
+ unsigned int maxReqSize;
+ unsigned int allocated;
+ unsigned int accAllocated;
+ unsigned int accFreed;
+ unsigned int max_alloc;
+ }
+ MEM_STATS;
+
+
+
+ /*************************** Global Variables *********************************/
+
+ int memPoolsInitialised = 0;
+
+ unsigned int memBlockSize[] = { 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288 };
+ /*unsigned int memBlockNum[] = { 400, 1600, 17000, 8192, 13440, 512, 384, 4352, 900, 7000, 256, 2048, 1024, 128, 128, 256, 6000, 2500, 380, 170, 85, 40, 30, 120, 40, 2, 1, 2, 2 };*/
+ unsigned int memBlockNum[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ unsigned int memBlkGrowthNum[] = { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+#define NUM_OF_POOLS (sizeof( memBlockSize ) / sizeof( unsigned int ))
+
+ static unsigned int memBlkGrowths[NUM_OF_POOLS];
+
+#ifdef STATIC_MEMORY_POOL
+ static char pHeap[MEM_SIZE];
+#else
+ static char *pHeap;
+#endif
+ static char* pReservedHeapMem;
+ static char* pMemPools[NUM_OF_POOLS];
+
+ static unsigned int initialHeapSize = MEM_SIZE;
+ static unsigned int usedHeapSize = 0;
+ static unsigned int reservedHeapSize = 0;
+ static unsigned int totalSystemAllocMem = 0;
+ static unsigned int numOfSystemAllocs = 0;
+
+ static MEM_STATS memStats[NUM_OF_POOLS];
+ static unsigned int allocatedMem = 0;
+ static unsigned int maxAllocMem = 0;
+
+
+
+ /*************************** Function Prototypes ******************************/
+
+ void initAllMemPools(void);
+ char* initMemPool(int poolId, int memBlockSize, int numOfMemBlocks, char** startAddress);
+ void* myMalloc(size_t size);
+ void myFree(void* ptr);
+ void displayMemStats(void);
+ void increaseMemPoolSize(unsigned int poolId);
+
+
+
+ /*************************** Function Definitions *****************************/
+
+ /*******************************************************************************
+ *
+ * Function: PortMallocInit
+ *
+ * Args: void
+ *
+ * Returns: void
+ *
+ * Description: API function which initialises the fixed size memory pools. Can
+ * be called multiple times in a session, but is only effective the
+ * first time it is called.
+ *
+ *******************************************************************************/
+
+ void PortMallocInit(void)
+ {
+ if (0 == memPoolsInitialised)
+ {
+ initAllMemPools();
+ }
+ }
+
+
+
+
+
+ int PortMallocGetMaxMemUsed(void)
+ {
+ return (int)maxAllocMem;
+ }
+
+
+
+ /*******************************************************************************
+ *
+ * Function: PortMallocSetPoolSize
+ *
+ * Args: Pool size (size_t)
+ *
+ * Returns: void
+ *
+ * Description: API function used to set the initial heap size. Note this can be
+ * called at any time, but is only effective if the memory manager
+ * has not already been initialised.
+ *
+ *******************************************************************************/
+
+ void PortMallocSetPoolSize(size_t size)
+ {
+#if !defined(STATIC_MEMORY_POOL) && !defined(RTXC_PARTITION_MEMORY)
+ if (!memPoolsInitialised)
+ {
+ initialHeapSize = (unsigned int)size;
+ }
+#else
+ (void)size;
+#endif
+ }
+
+
+
+ /*******************************************************************************
+ *
+ * Function: PortMallocGetPoolSize
+ *
+ * Args: void
+ *
+ * Returns: Pool Size (int)
+ *
+ * Description: API function to return the initial heap size.
+ *
+ *******************************************************************************/
+
+ int PortMallocGetPoolSize(void)
+ {
+ return (int)initialHeapSize;
+ }
+
+
+
+ /*******************************************************************************
+ *
+ * Function: initAllMemPools
+ *
+ * Args: void
+ *
+ * Returns: void
+ *
+ * Description: Internal function which is used to initialise all of the
+ * memory pools. Note it can be called many times but is only
+ * effective the first time it is called.
+ *
+ *******************************************************************************/
+
+ void initAllMemPools(void)
+ {
+ char *availableMemStartAddress;
+
+ if (0 == memPoolsInitialised)
+ {
+ int ii;
+
+ /* Calculate the required heap size */
+ for (ii = 0; ii < NUM_OF_POOLS; ii++)
+ {
+ usedHeapSize += (memBlockSize[ii] + MEM_BLOCK_HDR) * memBlockNum[ii];
+ }
+
+ if (initialHeapSize < usedHeapSize)
+ {
+ /* Insuffucient heap memory; abort initialisation */
+ return;
+ }
+
+
+#if defined(STATIC_MEMORY_POOL)
+ /* pHead has already been allocated, statically. Don't need to do anything. */
+#elif defined(RTXC_PARTITION_MEMORY)
+ /* Grab the one and only block in HEAP_MAP. */
+ pHeap = KS_alloc(HEAP_MAP);
+ /* MEM_SIZE has better equal the size of HEAP_MAP's block. */
+ PORT_ASSERT(MEM_SIZE == KS_inqmap(HEAP_MAP));
+#else
+ /* Use the system malloc for heap allocation. */
+
+ pHeap = (char*)malloc(initialHeapSize);
+#endif
+ if (0 == pHeap)
+ {
+ /* Unable to get memory for heap; abort initialisation */
+ return;
+ }
+
+ totalSystemAllocMem = initialHeapSize;
+ numOfSystemAllocs++;
+ reservedHeapSize = initialHeapSize - usedHeapSize;
+
+ /* Initialise each memory pool */
+ availableMemStartAddress = pHeap;
+
+ for (ii = 0; ii < NUM_OF_POOLS; ii++)
+ {
+ pMemPools[ii] = 0;
+
+ if (0 != memBlockNum[ii])
+ {
+ pMemPools[ii] = initMemPool(ii, memBlockSize[ii] + MEM_BLOCK_HDR, memBlockNum[ii], &availableMemStartAddress);
+ }
+ }
+
+ pReservedHeapMem = availableMemStartAddress;
+
+ memPoolsInitialised = 1;
+ }
+ }
+
+
+
+ /*******************************************************************************
+ *
+ * Function: initMemPool
+ *
+ * Args: Pool ID (int), Memory Block Size (int), Number of Memory Blocks
+ * (int), Heap Memory Start Address (char**)
+ *
+ * Returns: Memory Pool Start Address (char*)
+ *
+ * Description: Internal function used to fill a specified memory pool with a
+ * specified number of memory blocks of a specified size. The heap
+ * memory start address is adjusted to point to the next available
+ * memory following the newly created pool.
+ *
+ *******************************************************************************/
+
+ char* initMemPool(int poolId, int memBlockSize, int numOfMemBlocks, char** startAddress)
+ {
+ char* pPrevMemBlock = 0;
+ char* pCurrMemBlock = 0;
+ char* pStartMemPool = 0;
+ int ii;
+
+ for (ii = 0; ii < numOfMemBlocks; ii++)
+ {
+ pCurrMemBlock = &((*startAddress)[ii*memBlockSize]);
+
+ *((unsigned int*)pCurrMemBlock) = poolId;
+
+ if (0 != pPrevMemBlock)
+ {
+ ((unsigned int*)pPrevMemBlock)[NEXT_BLOCK_PTR_OFFSET] = (unsigned int)pCurrMemBlock;
+ }
+
+ pPrevMemBlock = pCurrMemBlock;
+ }
+
+ ((unsigned int*)pPrevMemBlock)[NEXT_BLOCK_PTR_OFFSET] = 0;
+
+ pStartMemPool = *startAddress;
+
+ *startAddress = (*startAddress) + (ii * memBlockSize);
+
+ return pStartMemPool;
+ }
+
+
+
+ /*******************************************************************************
+ *
+ * Function: PortMalloc
+ *
+ * Args: Size (size_t)
+ *
+ * Returns: Pointer to memory block (void*)
+ *
+ * Description: API function which is used by the application to request memory.
+ * A null pointer is returned if the memory manager is unable to
+ * satisfy the request.
+ *
+ *******************************************************************************/
+
+ void* PortMalloc(size_t size)
+ {
+ int poolId;
+ char *pMemBlock;
+ int ii;
+
+ /* Make sure the memory manager has been initialised */
+ if (0 == memPoolsInitialised)
+ {
+ initAllMemPools();
+ }
+
+ poolId = NUM_OF_POOLS;
+ pMemBlock = 0;
+
+ /* Find the best fit memory block */
+ for (ii = 0; ii < NUM_OF_POOLS; ii++)
+ {
+ if (memBlockSize[ii] >= size)
+ {
+ poolId = ii;
+
+ break;
+ }
+ }
+
+ /* Ensure that the requested size is not larger than the largest block size */
+ if (NUM_OF_POOLS > poolId)
+ {
+ /* Search the selected memory pool for a memory block; if there are none
+ then try to create some more blocks. If this is not possible then
+ search the next largest memory block pool. Repeat until either a block
+ is found, or there are no pools left */
+ for (ii = poolId; ii < NUM_OF_POOLS; ii++)
+ {
+#ifdef ALLOW_POOL_GROWTHS
+ /* If there are no blocks left, try to create some more */
+ if (0 == pMemPools[ii])
+ {
+ increaseMemPoolSize(ii);
+ }
+#endif /* ALLOW_POOL_GROWTHS */
+
+ if (0 != pMemPools[ii])
+ {
+ /* Remove the memory block from the pool linked-list */
+ pMemBlock = pMemPools[ii];
+
+ pMemPools[ii] = (char*)(((unsigned int*)pMemBlock)[NEXT_BLOCK_PTR_OFFSET]);
+
+#ifdef MEM_MGR_STATS
+ /* Record the requested size in the memory block header - this is used
+ by PortFree to determine how much requested memory has been free'd */
+ *((unsigned int*)pMemBlock) = ii | (size << MEM_REQ_SIZE_BIT_SHIFT);
+#endif /* MEM_MGR_STATS */
+
+ /* Adjust the memory block pointer to point to the useful portion of the
+ memory block, ie beyond the header */
+ pMemBlock = pMemBlock + MEM_BLOCK_HDR;
+
+#ifdef MEM_MGR_STATS
+ /* Update the memory statistics */
+ allocatedMem += size;
+
+ if (allocatedMem > maxAllocMem)
+ {
+ maxAllocMem = allocatedMem;
+ }
+
+ memStats[ii].accReqSize += size;
+ memStats[ii].accAllocated++;
+ memStats[ii].allocated++;
+
+ if (memStats[ii].maxReqSize < size)
+ {
+ memStats[ii].maxReqSize = size;
+ }
+
+ if (memStats[ii].allocated > memStats[ii].max_alloc)
+ {
+ memStats[ii].max_alloc = memStats[ii].allocated;
+ }
+#endif /* MEM_MGR_STATS */
+ break;
+ }
+ }
+ }
+
+ return (void*)pMemBlock;
+ }
+
+
+#ifdef ALLOW_POOL_GROWTHS
+ /*******************************************************************************
+ *
+ * Function: increaseMemPoolSize
+ *
+ * Args: Pool ID (unsigned int)
+ *
+ * Returns: void
+ *
+ * Description: Increases the number of blocks in a given pool by the number
+ * specified in the array memBlkGrowthNum if there is memory
+ * available. Memory is allocated from the heap reserve if
+ * availabe, else it is requested from the system (if the
+ * compilation flag ALLOW_ADDITIONAL_SYS_MEM_ALLOCS is defined. If
+ * there is insufficient memory then the operation is aborted
+ * without notification to the calling code.
+ *
+ *******************************************************************************/
+
+ void increaseMemPoolSize(unsigned int poolId)
+ {
+ unsigned int requiredMemSize = memBlkGrowthNum[poolId] * (memBlockSize[poolId] + MEM_BLOCK_HDR);
+
+ /* See if there is enough heap reserve memory */
+ if (requiredMemSize <= reservedHeapSize)
+ {
+ /* We're in luck; there's enough space */
+ pMemPools[poolId] = initMemPool(poolId, memBlockSize[poolId] + MEM_BLOCK_HDR, memBlkGrowthNum[poolId], &pReservedHeapMem);
+
+ memBlockNum[poolId] += memBlkGrowthNum[poolId];
+
+ reservedHeapSize -= requiredMemSize;
+ usedHeapSize += requiredMemSize;
+
+#ifdef MEM_MGR_STATS
+ memBlkGrowths[poolId]++;
+#endif /* MEM_MGR_STATS */
+ }
+#ifdef ALLOW_ADDITIONAL_SYS_MEM_ALLOCS
+ else
+ {
+ /* There's not enough memory in the heap reserve, so request it from the system */
+ char* pStartAddress = (char*)malloc(requiredMemSize);
+
+ if (0 != pStartAddress)
+ {
+ /* The system has allocated some memory, so let's make some more blocks */
+ pMemPools[poolId] = initMemPool(poolId, memBlockSize[poolId] + MEM_BLOCK_HDR, memBlkGrowthNum[poolId], &pStartAddress);
+
+ memBlockNum[poolId] += memBlkGrowthNum[poolId];
+
+ totalSystemAllocMem += requiredMemSize;
+ numOfSystemAllocs++;
+
+#ifdef MEM_MGR_STATS
+ memBlkGrowths[poolId]++;
+#endif /* MEM_MGR_STATS */
+ }
+ }
+#endif /* ALLOW_ADDITIONAL_SYS_MEM_ALLOCS */
+ }
+#endif /* ALLOW_POOL_GROWTHS */
+
+
+
+ /*******************************************************************************
+ *
+ * Function: PortFree
+ *
+ * Args: Memory Block Pointer (void*)
+ *
+ * Returns: void
+ *
+ * Description: API function used by the application code to return a memory
+ * block to the appropriate pool. Note that this function is not
+ * able to handle null or stale memory block pointers; calling this
+ * function under these conditions will result in unpredictable
+ * behavior.
+ *
+ *******************************************************************************/
+
+ void PortFree(void* pMem)
+ {
+ unsigned int tmpVal;
+ unsigned char poolId;
+ char* pCurrentHead;
+#ifdef MEM_MGR_STATS
+ unsigned int reqMemSize;
+#endif
+
+ /* What is the memory block pool id ? */
+ tmpVal = ((unsigned int*)pMem)[-MEM_BLOCK_HDR_OFFSET+MEM_POOL_ID_OFFSET];
+ poolId = tmpVal & MEM_POOL_ID_MASK;
+
+ /* Add the memory block to the appropriate pool */
+ pCurrentHead = pMemPools[poolId];
+ ((unsigned int*)pMem)[-MEM_BLOCK_HDR_OFFSET+NEXT_BLOCK_PTR_OFFSET] = (unsigned int)pCurrentHead;
+ pMemPools[poolId] = (char*) & (((unsigned int*)pMem)[-MEM_BLOCK_HDR_OFFSET]);
+
+#ifdef MEM_MGR_STATS
+ /* What was the requested memory size ? */
+ reqMemSize = tmpVal >> MEM_REQ_SIZE_BIT_SHIFT;
+
+ allocatedMem -= reqMemSize;
+
+ PORT_ASSERT(allocatedMem >= 0);
+
+ memStats[poolId].accFreed++;
+ memStats[poolId].allocated--;
+#endif /* MEM_MGR_STATS */
+ }
+
+
+
+ /*******************************************************************************
+ *
+ * Function: displayMemStats
+ *
+ * Args: void
+ *
+ * Returns: void
+ *
+ * Description: API function used to display the overall memory and individual
+ * memory pool statistics to standard output.
+ *
+ *******************************************************************************/
+
+ void displayMemStats(void)
+ {
+ unsigned int totBNum = 0;
+ unsigned int totGrowths = 0;
+ unsigned int totAlloc = 0;
+ unsigned int totAccAlloc = 0;
+ unsigned int totAccFreed = 0;
+ unsigned int totMaxAlloc = 0;
+ unsigned int totMemWithOH = 0;
+ unsigned int totMem = 0;
+ unsigned int bytesAllocWithOH = 0;
+ unsigned int bytesAlloc = 0;
+ unsigned int maxBytesAllocWithOH = 0;
+ unsigned int maxBytesAlloc = 0;
+ unsigned int ii;
+
+ printf("\nPool ID BlkSz AvReqSz MaxReqSz NumBlk Growths Alloc AccAlloc AccFreed MaxAlloc Alloc(b) MaxA(b)\n");
+ printf("--------------------------------------------------------------------------------------------------------\n");
+
+ for (ii = 0; ii < NUM_OF_POOLS; ii++)
+ {
+ unsigned int avReqSize = 0;
+
+ if (0 != memStats[ii].accAllocated)
+ {
+ avReqSize = memStats[ii].accReqSize / memStats[ii].accAllocated;
+ }
+
+ printf(" %4i %6i %6i %6i %7i %7i %7i %7i %7i %7i %8i %8i\n", ii, memBlockSize[ii], avReqSize, memStats[ii].maxReqSize, memBlockNum[ii], memBlkGrowths[ii], memStats[ii].allocated, memStats[ii].accAllocated, memStats[ii].accFreed, memStats[ii].max_alloc, (memBlockSize[ii]*memStats[ii].allocated), (memBlockSize[ii]*memStats[ii].max_alloc));
+
+ totBNum += memBlockNum[ii];
+ totGrowths += memBlkGrowths[ii];
+ totAlloc += memStats[ii].allocated;
+ totAccAlloc += memStats[ii].accAllocated;
+ totAccFreed += memStats[ii].accFreed;
+ totMaxAlloc += memStats[ii].max_alloc;
+
+ totMemWithOH += (memBlockSize[ii] + MEM_BLOCK_HDR) * memBlockNum[ii];
+ totMem += memBlockSize[ii] * memBlockNum[ii];
+ bytesAllocWithOH += memStats[ii].allocated * (memBlockSize[ii] + MEM_BLOCK_HDR);
+ bytesAlloc += memStats[ii].allocated * memBlockSize[ii];
+ maxBytesAllocWithOH += memStats[ii].max_alloc * (memBlockSize[ii] + MEM_BLOCK_HDR);
+ maxBytesAlloc += memStats[ii].max_alloc * memBlockSize[ii];
+ }
+
+ printf("--------------------------------------------------------------------------------------------------------\n");
+ printf("Total %7i %7i %7i %7i %7i %7i %8i %8i\n\n", totBNum, totGrowths, totAlloc, totAccAlloc, totAccFreed, totMaxAlloc, bytesAlloc, maxBytesAlloc);
+ printf("Total Memory %9i bytes\n", totMemWithOH);
+ printf("Total Memory %9i bytes (without overhead)\n", totMem);
+ printf("Allocated Memory %9i bytes\n", bytesAllocWithOH);
+ printf("Allocated Memory %9i bytes (without overhead)\n", bytesAlloc);
+ printf("Max Alloc Memory %9i bytes\n", maxBytesAllocWithOH);
+ printf("Max Alloc Memory %9i bytes (without overhead)\n", maxBytesAlloc);
+ printf("\nReq Alloc Memory %9i bytes\n", allocatedMem);
+ printf("Max Rq Alloc Mem %9i bytes\n\n", maxAllocMem);
+
+ printf("Used Heap Size %9i bytes\n", usedHeapSize);
+ printf("Reserved Heap %9i bytes\n", reservedHeapSize);
+ printf("Total Sys Alloc %9i bytes\n", totalSystemAllocMem);
+ printf("Num of Sys Alloc %9i\n", numOfSystemAllocs);
+
+ printf("\n");
+ }
+
+
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+
+#endif /* FIXED_SIZE_MEM_BLOCK_SCHEME */
diff --git a/portable/src/pmemory.c b/portable/src/pmemory.c
new file mode 100644
index 0000000..f00427d
--- /dev/null
+++ b/portable/src/pmemory.c
@@ -0,0 +1,956 @@
+/*---------------------------------------------------------------------------*
+ * pmemory.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+
+#include "passert.h"
+#include "pcrc.h"
+#include "pmemory.h"
+#include "PFileSystem.h"
+#include "PStackTrace.h"
+#include "passert.h"
+#include "pmemory_ext.h"
+#include "pmutex.h"
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+static unsigned int gNbInit = 0;
+static PFile* gFile = NULL;
+static ESR_BOOL isLogEnabled = ESR_TRUE;
+
+#ifdef PMEM_MAP_TRACE
+static asr_uint32_t gMaxAlloc = -1;
+static asr_uint32_t gCurAlloc = -1;
+#endif
+
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+static size_t gMemPoolSize = (3*1024*1024); /* default value: 3M */
+#endif
+
+#ifdef USE_THREAD
+static MUTEX memMutex;
+#endif
+
+#define MAX_MEM_TAG 256
+
+/* Only PMEM_MAP_TRACE has been defined, could do other memory logging/debugging */
+#ifdef PMEM_MAP_TRACE
+
+#define PMEM_STACKTRACE 0
+/* If enabled, logs individual memory allocation, reallocation, free operations */
+#define PMEM_LOG_LOWLEVEL 0
+#elif defined(WIN32)
+#pragma message("No PMEM_MAP_TRACE")
+#endif
+
+typedef struct MemoryData_t
+{
+#ifdef PMEM_MAP_TRACE
+ int index;
+#endif
+ size_t size;
+#if PMEM_STACKTRACE
+ /**
+ * Stacktrace of where the memory was allocated from.
+ */
+ const LCHAR* stackTrace;
+ /**
+ * Pointer to next memory allocation associated with the same tag.
+ */
+ struct MemoryData_t* next;
+ /**
+ * Pointer to last memory allocation associated with the same tag.
+ */
+ struct MemoryData_t* last;
+#endif
+}
+MemoryData;
+
+#ifdef PMEM_MAP_TRACE
+typedef struct MemMapEntry_t
+{
+ /**
+ * Memory tag/ID associated with allocation.
+ */
+ const LCHAR* tag;
+ asr_uint32_t curAlloc;
+ asr_uint32_t maxAlloc;
+ unsigned int crc;
+ /**
+ * First memory allocation associated with this tag.
+ * Memory that has been deallocated will not show up on this list.
+ */
+ MemoryData* first;
+ /**
+ * Last memory allocation associated with this tag.
+ * Memory that has been deallocated will not show up on this list.
+ */
+ MemoryData* last;
+}
+MemMapEntry;
+
+static MemMapEntry gMemoryMap[MAX_MEM_TAG];
+#endif
+
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+extern ESR_ReturnCode memory_pool_creation_status; /* Verify that memory pool actually was created */
+#define malloc PortNew
+#define free PortDelete
+#endif
+
+
+#if PMEM_STACKTRACE
+static ESR_ReturnCode getStackTrace(LCHAR* stackTrace, size_t* len)
+{
+ ESR_BOOL isInit;
+ ESR_ReturnCode rc;
+
+ rc = PStackTraceIsInitialized(&isInit);
+ if (rc == ESR_SUCCESS && isInit)
+ {
+ LCHAR* index;
+ size_t bufferLen = *len;
+ size_t i;
+
+ rc = PStackTraceGetValue(stackTrace, &bufferLen);
+ if (rc == ESR_SUCCESS)
+ {
+ for (i = 0; i < 2; ++i)
+ {
+ rc = PStackTracePopLevel(stackTrace);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, "[%s:%d] PStackTracePopLevel failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ }
+ index = stackTrace;
+ while (index)
+ {
+ index = LSTRSTR(index, L(" at\n"));
+ if (index != NULL)
+ *(index + 3) = L(' ');
+ }
+ }
+ else if (rc == ESR_NOT_SUPPORTED)
+ LSTRCPY(stackTrace, L(""));
+ else if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, "[%s:%d] PStackTraceGetValue failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ }
+ else
+ LSTRCPY(stackTrace, L("(null)"));
+ *len = LSTRLEN(stackTrace);
+ return ESR_SUCCESS;
+CLEANUP:
+ return rc;
+}
+#endif /* PMEM_STACKTRACE */
+
+#ifdef PMEM_MAP_TRACE
+static int getIndex(const LCHAR *key)
+{
+ unsigned int crc = ~pcrcComputeString(key);
+ int initialIdx = (int)(crc % MAX_MEM_TAG);
+ int idx = initialIdx;
+
+ for (;;)
+ {
+ if (gMemoryMap[idx].tag == NULL)
+ {
+ /* found an empty slot, use it. */
+ gMemoryMap[idx].tag = key;
+ gMemoryMap[idx].curAlloc = 0;
+ gMemoryMap[idx].maxAlloc = 0;
+ gMemoryMap[idx].crc = crc;
+ gMemoryMap[idx].first = NULL;
+ gMemoryMap[idx].last = NULL;
+#if PMEM_LOG_LOWLEVEL
+ if (gFile != NULL)
+ pfprintf(gFile, L("pmem|newtag|%s|%d|\n"), key, idx);
+#endif
+ return idx;
+ }
+
+ if (gMemoryMap[idx].crc == crc &&
+ LSTRCMP(gMemoryMap[idx].tag, key) == 0)
+ {
+ /* found a matching slot, return it */
+ return idx;
+ }
+
+ if (++idx == MAX_MEM_TAG)
+ {
+ /* Look at next slot and wrap around. */
+ idx = 0;
+ }
+ if (idx == initialIdx)
+ return -1;
+ }
+}
+#endif
+
+/* Not thread-safe. But do not expect user calls this function on different threads simultaneously */
+ESR_ReturnCode PMemorySetPoolSize(size_t size)
+{
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+ if (gNbInit > 0)
+ return ESR_INVALID_STATE;
+
+ gMemPoolSize = size;
+ return ESR_SUCCESS;
+#else
+ return ESR_NOT_SUPPORTED;
+#endif
+}
+
+ESR_ReturnCode PMemoryGetPoolSize(size_t *size)
+{
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+ *size = gMemPoolSize;
+ return ESR_SUCCESS;
+#else
+ return ESR_NOT_SUPPORTED;
+#endif
+}
+
+/* it is not thread safe: hard to protect the createMutex()
+ * could fix it by using static mutex initialization in some OS,
+ * but does not work with our own pthread implementation for vxworks
+ * SUPPOSE the user just calls this function once
+ */
+ESR_ReturnCode PMemInit(void)
+{
+ ESR_ReturnCode init_status;
+
+ if (gNbInit > 0)
+ return ESR_INVALID_STATE;
+
+ init_status = createMutex(&memMutex, ESR_FALSE);
+
+ if (init_status == ESR_SUCCESS)
+ {
+ ++gNbInit;
+#ifdef PMEM_MAP_TRACE
+ memset(gMemoryMap, 0, sizeof(gMemoryMap));
+#endif
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+ PortMemSetPoolSize(gMemPoolSize);
+ PortMemoryInit();
+ /* There is no friggin' way to pass the status of the memory initialization, because of the damn macros and all the other crap */
+ /* So I am checking the value of an external variable, this sucks, but I can't ignore something this important */
+ if (memory_pool_creation_status == ESR_SUCCESS)
+ {
+ /* Reset this because with all the layers of crap, I can't guarantee we'll get to the bottom layer on a re-init */
+ memory_pool_creation_status = ESR_FATAL_ERROR;
+ }
+ else
+ {
+ pfprintf(PSTDERR, L("ESR_INVALID_STATE: Memory Pool Could Not Be Created\n"));
+ PortMemoryTerm();
+ unlockMutex(&memMutex);
+ deleteMutex(&memMutex);
+ init_status = ESR_INVALID_STATE;
+ }
+#endif
+ }
+ else
+ {
+ deleteMutex(&memMutex);
+ }
+
+ // Initialize global static variables
+ gCurAlloc = 0;
+ gMaxAlloc = 0;
+
+ return (init_status);
+}
+
+/* it is not thread safe: hard to protect the deleteMutex()
+ * could fix it by using static mutex initialization in some OS,
+ * but does not work with our own pthread implementation for vxworks
+ * SUPPOSE the user just calls this function once
+ */
+ESR_ReturnCode PMemShutdown(void)
+{
+#ifdef PMEM_MAP_TRACE
+ size_t i;
+#endif
+
+ if (gNbInit == 0)
+ return ESR_INVALID_STATE;
+ if (gNbInit == 1)
+ {
+#ifdef PMEM_MAP_TRACE
+ for (i = 0; i < MAX_MEM_TAG; ++i)
+ {
+ free((LCHAR*) gMemoryMap[i].tag);
+ gMemoryMap[i].tag = NULL;
+ }
+#endif
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+ PortMemoryTerm();
+#endif
+ deleteMutex(&memMutex);
+ }
+ gNbInit--;
+
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PMemSetLogFile(PFile* file)
+{
+ if (gNbInit == 0)
+ return ESR_INVALID_STATE;
+
+ lockMutex(&memMutex);
+ gFile = file;
+ unlockMutex(&memMutex);
+
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PMemDumpLogFile(void)
+{
+ ESR_ReturnCode rc;
+
+ if (gNbInit == 0)
+ return ESR_INVALID_STATE;
+
+ lockMutex(&memMutex);
+ if (gFile != NULL)
+ {
+ /* Hide gFile from memory report */
+/* CHK(rc, gFile->hideMemoryAllocation(gFile));*/
+
+ rc = PMemReport(gFile);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
+ goto CLEANUP;
+ }
+ if (gFile != PSTDIN && gFile != PSTDOUT && gFile != PSTDERR)
+ {
+/* rc = gFile->destroy(gFile);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
+ goto CLEANUP;
+ }*/
+ pfclose ( gFile );
+ }
+ gFile = NULL;
+ }
+ unlockMutex(&memMutex);
+ return ESR_SUCCESS;
+CLEANUP:
+ unlockMutex(&memMutex);
+ return rc;
+}
+
+ESR_ReturnCode PMemSetLogEnabled(ESR_BOOL value)
+{
+ lockMutex(&memMutex);
+ isLogEnabled = value;
+ unlockMutex(&memMutex);
+
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PMemLogFree(void* ptr)
+{
+ MemoryData* data;
+#ifdef PMEM_MAP_TRACE
+ MemMapEntry* e;
+#endif
+#if PMEM_STACKTRACE && PMEM_LOG_LOWLEVEL
+ ESR_ReturnCode rc;
+#endif
+
+ if (ptr == NULL || gNbInit == 0)
+ return ESR_SUCCESS;
+
+ lockMutex(&memMutex);
+
+ data = (MemoryData*)(((unsigned char*) ptr) - sizeof(MemoryData));
+#ifdef PMEM_MAP_TRACE
+ e = gMemoryMap + data->index;
+ passert(data->index >= 0 && data->index <= MAX_MEM_TAG);
+ if (isLogEnabled)
+ {
+ passert(e->curAlloc >= data->size);
+ e->curAlloc -= data->size;
+
+ passert(gCurAlloc >= data->size);
+ gCurAlloc -= data->size;
+
+ data->size = 0;
+ }
+#if PMEM_STACKTRACE
+ if (e->first != NULL && e->first == data)
+ e->first = data->next;
+ if (e->last != NULL && e->last == data)
+ e->last = data->last;
+ if (data->last != NULL)
+ data->last->next = data->next;
+ if (data->next != NULL)
+ {
+ data->next->last = data->last;
+ data->next = NULL;
+ }
+ data->last = NULL;
+#endif
+#if PMEM_LOG_LOWLEVEL
+ if (gFile != NULL && isLogEnabled)
+ {
+#if PMEM_STACKTRACE
+ LCHAR stackTrace[P_MAX_STACKTRACE];
+ size_t len = P_MAX_STACKTRACE;
+
+ rc = getStackTrace(stackTrace, &len);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, "[%s:%d] getStackTrace failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ pfprintf(gFile, L("pmem|free|%s|%s|%d|0x%x|%s|\n"), e->tag, data->stackTrace, data->size, ptr, stackTrace);
+#else
+ pfprintf(gFile, L("pmem|free|%s|%d|0x%x\n"), e->tag, data->size, ptr);
+#endif /* PMEM_STACKTRACE */
+ }
+#endif /* PMEM_LOG_LOWLEVEL */
+#endif /* PMEM_MAP_TRACE */
+
+ unlockMutex(&memMutex);
+ return ESR_SUCCESS;
+#if PMEM_STACKTRACE && PMEM_LOG_LOWLEVEL
+CLEANUP:
+ unlockMutex(&memMutex);
+ return rc;
+#endif
+}
+
+ESR_ReturnCode PMemReport(PFile* file)
+{
+#define TAG_SIZE 52
+#ifdef PMEM_MAP_TRACE
+ asr_uint32_t totalAlloc = 0;
+ size_t i;
+ MemMapEntry* e;
+ unsigned int crc;
+ LCHAR truncatedTag[TAG_SIZE];
+ size_t len;
+ LCHAR TAG_PREFIX[] = L("...");
+ const size_t TAG_PREFIX_SIZE = LSTRLEN(TAG_PREFIX);
+ const size_t countToCopy = (TAG_SIZE - 1) - TAG_PREFIX_SIZE;
+#endif
+#if PMEM_STACKTRACE
+ MemoryData* data;
+#endif
+
+ if (gNbInit == 0)
+ return ESR_INVALID_STATE;
+ if (file == NULL)
+ {
+ file = gFile;
+ if (file == NULL)
+ return ESR_SUCCESS;
+ }
+
+ lockMutex(&memMutex);
+#ifdef PMEM_MAP_TRACE
+ if (gFile != NULL)
+ {
+ for (i = 0, e = gMemoryMap; i < MAX_MEM_TAG; ++i, ++e)
+ {
+ if (e->tag == NULL)
+ continue;
+ crc = ~pcrcComputeString(e->tag);
+ if (crc != e->crc)
+ pfprintf(gFile, L("pmem|-|0|corrupt|%d|\n"), i);
+ }
+ }
+
+ pfprintf(file, L("%-52s %10s %15s\n"), L("Memory tag"), L("Cur. Alloc"), L("Max. Alloc"));
+
+ for (i = 0, e = gMemoryMap; i < MAX_MEM_TAG; ++i, ++e)
+ {
+ if (e->tag == NULL)
+ continue;
+ crc = ~pcrcComputeString(e->tag);
+ if (crc != e->crc)
+ pfprintf(file, L("**********%04d********** %38u %15u\n"), i, e->curAlloc, e->maxAlloc);
+ else
+ {
+ len = LSTRLEN(e->tag);
+
+ if (len > TAG_SIZE - 1)
+ {
+ LSTRCPY(truncatedTag, TAG_PREFIX);
+ LSTRCPY(truncatedTag + TAG_PREFIX_SIZE, e->tag + (len - countToCopy));
+ passert(LSTRLEN(truncatedTag) == TAG_SIZE - 1);
+ }
+ else
+ LSTRCPY(truncatedTag, e->tag);
+ pfprintf(file, L("%-52s %10u %15u\n"), truncatedTag, e->curAlloc, e->maxAlloc);
+ }
+#if PMEM_STACKTRACE
+ data = gMemoryMap[i].first;
+ while (data)
+ {
+ if (data->size != 0 && data->stackTrace != NULL)
+ {
+ LCHAR stackTrace[P_MAX_STACKTRACE];
+ LCHAR* index;
+
+ LSTRCPY(stackTrace, data->stackTrace);
+ index = stackTrace;
+ while (index)
+ {
+ index = LSTRSTR(index, L(" at "));
+ if (index != NULL)
+ *(index + 3) = L('\n');
+ }
+ pfprintf(file, L("StackTrace:\n%s\n\n"), stackTrace);
+ }
+ data = data->next;
+ }
+#endif
+ passert(e->curAlloc >= 0);
+ totalAlloc += e->curAlloc;
+ }
+ pfprintf(file, L("%-52s %10u %15u\n"), L("Total"), totalAlloc, gMaxAlloc);
+ passert(totalAlloc == gCurAlloc);
+#else
+ /* not support */
+#endif /* PMEM_MAP_TRACE */
+ unlockMutex(&memMutex);
+
+ return ESR_SUCCESS;
+}
+/*
+DESCRIPTION
+ The functionality described on this reference page is aligned with the ISO C standard. Any conflict between the requirements described here and the ISO C standard is unintentional. This volume of IEEE Std 1003.1-2001 defers to the ISO C standard.
+The malloc() function shall allocate unused space for an object whose size in bytes is specified by size and whose value is unspecified.
+
+The order and contiguity of storage allocated by successive calls to malloc() is unspecified. The pointer returned if the allocation succeeds shall be suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object in the space allocated (until the space is explicitly freed or reallocated). Each such allocation shall yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer shall be returned. If the size of the space requested is 0, the behavior is implementation-defined: the value returned shall be either a null pointer or a unique pointer.
+
+RETURN VALUE
+Upon successful completion with size not equal to 0, malloc() shall return a pointer to the allocated space. If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() shall be returned. Otherwise, it shall return a null pointer and set errno to indicate the error.
+*/
+#ifdef PMEM_MAP_TRACE
+void *pmalloc(size_t nbBytes, const LCHAR* tag, const LCHAR* file, int line)
+#else
+void *pmalloc(size_t nbBytes)
+#endif
+{
+ MemoryData* data;
+ void* result = NULL;
+ size_t actualSize;
+#ifdef PMEM_MAP_TRACE
+ int idx;
+ MemMapEntry* e;
+#endif
+#if PMEM_STACKTRACE
+ size_t stackTraceSize = P_MAX_STACKTRACE;
+ LCHAR* stackTrace;
+ ESR_BOOL isInit;
+ ESR_ReturnCode rc;
+#endif
+
+ if (gNbInit == 0)
+ return NULL;
+
+ lockMutex(&memMutex);
+
+#ifdef PMEM_MAP_TRACE
+ if (tag == NULL)
+ tag = file;
+ passert(tag != NULL);
+
+ idx = getIndex(tag);
+ if (idx == -1)
+ {
+ pfprintf(PSTDERR, L("ESR_INVALID_STATE: pmalloc() ran out of slots"));
+ goto CLEANUP;
+ }
+ if (gMemoryMap[idx].tag == tag)
+ {
+ /* This is a new key, allocate memory for it */
+ gMemoryMap[idx].tag = malloc(sizeof(LCHAR) * (LSTRLEN(tag) + 1));
+ if (gMemoryMap[idx].tag == NULL)
+ goto CLEANUP;
+ LSTRCPY((LCHAR*) gMemoryMap[idx].tag, tag);
+ }
+#endif
+ actualSize = sizeof(MemoryData) + nbBytes;
+
+ data = (MemoryData *) malloc(actualSize);
+ if (data == NULL)
+ {
+ /*
+ * printf("no space when alloc %d from file %s line %d\nmem usage: %d\n",
+ * nbBytes, file, line, PortMallocGetMaxMemUsed());
+ */
+ goto CLEANUP;
+ }
+
+#ifdef PMEM_MAP_TRACE
+ data->index = idx;
+#if PMEM_STACKTRACE
+ rc = PStackTraceIsInitialized(&isInit);
+ if (rc != ESR_SUCCESS)
+ goto CLEANUP;
+ if (isInit)
+ {
+ stackTrace = malloc(sizeof(LCHAR) * (stackTraceSize + 1));
+ if (stackTrace == NULL)
+ goto CLEANUP;
+ rc = getStackTrace(stackTrace, &stackTraceSize);
+ if (rc != ESR_SUCCESS)
+ goto CLEANUP;
+ /* Shrink stackTrace buffer */
+ passert(LSTRLEN(stackTrace) < P_MAX_STACKTRACE);
+ data->stackTrace = realloc(stackTrace, sizeof(LCHAR) * (LSTRLEN(stackTrace) + 1));
+ if (data->stackTrace == NULL)
+ {
+ free(stackTrace);
+ goto CLEANUP;
+ }
+ }
+ else
+ data->stackTrace = NULL;
+#endif
+
+ e = gMemoryMap + idx;
+
+#if PMEM_STACKTRACE
+ if (e->last != NULL)
+ e->last->next = data;
+ data->last = e->last;
+ data->next = NULL;
+ e->last = data;
+ if (e->first == NULL)
+ e->first = data;
+#endif
+#endif
+
+ if (isLogEnabled)
+ {
+ data->size = actualSize;
+#ifdef PMEM_MAP_TRACE
+ e->curAlloc += actualSize;
+ if (e->maxAlloc < e->curAlloc)
+ e->maxAlloc = e->curAlloc;
+
+ gCurAlloc += actualSize;
+ if (gMaxAlloc < gCurAlloc)
+ gMaxAlloc = gCurAlloc;
+#endif
+ }
+ else
+ data->size = 0;
+
+ result = (void*)(data + 1);
+
+#if PMEM_LOG_LOWLEVEL
+ if (gFile != NULL && isLogEnabled)
+
+ if (gFile != NULL)
+ {
+#if PMEM_STACKTRACE
+ pfprintf(gFile, L("pmem|alloc|%s|%d|0x%x|%s|\n"), tag, actualSize, result, data->stackTrace);
+#else
+ pfprintf(gFile, L("pmem|alloc|%s|%d|0x%x|\n"), tag, actualSize, result);
+#endif /* PMEM_STACKTRACE */
+ }
+#endif /* PMEM_LOG_LOWLEVEL */
+
+CLEANUP:
+ unlockMutex(&memMutex);
+ return result;
+}
+
+#ifdef PMEM_MAP_TRACE
+void *pcalloc(size_t nbItems, size_t itemSize, const LCHAR* tag, const LCHAR* file, int line)
+#else
+void *pcalloc(size_t nbItems, size_t itemSize)
+#endif
+{
+ void* result = NULL;
+
+ if (gNbInit == 1)
+ {
+#ifdef PMEM_MAP_TRACE
+ result = (MemoryData *)pmalloc(nbItems * itemSize, tag, file, line);
+#else
+ result = (MemoryData *)pmalloc(nbItems * itemSize);
+#endif
+ if (result != NULL)
+ memset(result, 0, nbItems * itemSize);
+ }
+ return (result);
+}
+
+/*
+DESCRIPTION
+The realloc() function changes the size of the memory object pointed to by ptr to the size specified by size. The contents of the object will remain unchanged up to the lesser of the new and old sizes. If the new size of the memory object would require movement of the object, the space for the previous instantiation of the object is freed. If the new size is larger, the contents of the newly allocated portion of the object are unspecified. If size is 0 and ptr is not a null pointer, the object pointed to is freed. If the space cannot be allocated, the object remains unchanged.
+If ptr is a null pointer, realloc() behaves like malloc() for the specified size.
+
+If ptr does not match a pointer returned earlier by calloc(), malloc() or realloc() or if the space has previously been deallocated by a call to free() or realloc(), the behaviour is undefined.
+
+The order and contiguity of storage allocated by successive calls to realloc() is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object in the space allocated (until the space is explicitly freed or reallocated). Each such allocation will yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer is returned.
+
+ RETURN VALUE
+Upon successful completion with a size not equal to 0, realloc() returns a pointer to the (possibly moved) allocated space. If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() is returned. If there is not enough available memory, realloc() returns a null pointer
+*/
+#ifdef PMEM_MAP_TRACE
+void *prealloc(void *ptr, size_t newSize, const LCHAR *file, int line)
+#else
+void *prealloc(void *ptr, size_t newSize)
+#endif
+{
+ MemoryData* oldData;
+ MemoryData* newData;
+ void *result = NULL;
+ size_t actualSize;
+#ifdef PMEM_MAP_TRACE
+ MemMapEntry* e;
+#endif
+ size_t oldSize;
+#if PMEM_STACKTRACE
+ const LCHAR* oldStackTrace;
+ MemoryData* oldNext;
+ MemoryData* oldLast;
+#endif
+ ESR_BOOL bMalloc = ESR_FALSE;
+
+ if (gNbInit == 0)
+ return NULL;
+
+ if (newSize == 0 && ptr != NULL)
+ {
+#ifdef PMEM_MAP_TRACE
+ pfree(ptr, file, line);
+#else
+ pfree(ptr);
+#endif
+ return NULL;
+ }
+ else if (ptr == NULL)
+ {
+#ifdef PMEM_MAP_TRACE
+ return pmalloc(newSize, NULL, file, line);
+#else
+ return pmalloc(newSize);
+#endif
+ }
+
+ lockMutex(&memMutex);
+
+ oldData = (MemoryData *)(((unsigned char *) ptr) - sizeof(MemoryData));
+ oldSize = oldData->size;
+ passert(oldSize >= 0);
+#if PMEM_STACKTRACE
+ oldStackTrace = oldData->stackTrace;
+ oldNext = oldData->next;
+ oldLast = oldData->last;
+#endif
+#ifdef PMEM_MAP_TRACE
+ e = gMemoryMap + oldData->index;
+#endif
+
+ actualSize = newSize + sizeof(MemoryData);
+ if (oldSize != actualSize)
+ {
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+ newData = (MemoryData *) PortNew(actualSize);
+ if (newData == NULL)
+ {
+ pfprintf(PSTDERR, L("OUT_OF_MEMORY: prealloc() failed at %s:%d"), __FILE__, __LINE__);
+ return NULL;
+ }
+ bMalloc = ESR_TRUE;
+ if (oldSize >= actualSize)
+ {
+ memcpy(newData, oldData, actualSize);
+ }
+ else
+ {
+ memcpy(newData, oldData, oldSize);
+ }
+ PortDelete(oldData);
+#else
+ newData = (MemoryData *) realloc(oldData, actualSize);
+ bMalloc = ESR_TRUE;
+#endif
+ }
+ else /* No change */
+ {
+ newData = oldData;
+ }
+
+#ifdef PMEM_MAP_TRACE
+ if (newData != NULL && bMalloc)
+ {
+ if (isLogEnabled)
+ {
+ e->curAlloc += actualSize - oldSize;
+ if (e->maxAlloc < e->curAlloc)
+ e->maxAlloc = e->curAlloc;
+
+ gCurAlloc += actualSize - oldSize;
+ if (gMaxAlloc < gCurAlloc)
+ gMaxAlloc = gCurAlloc;
+ }
+
+#if PMEM_STACKTRACE
+ newData->stackTrace = oldStackTrace;
+ newData->next = oldNext;
+ newData->last = oldLast;
+ if (newData->last != NULL)
+ newData->last->next = newData;
+ if (newData->next != NULL)
+ newData->next->last = newData;
+ if (e->first == oldData)
+ e->first = newData;
+ if (e->last == oldData)
+ e->last = newData;
+#endif
+ }
+#endif
+
+ if (newData != NULL)
+ {
+ newData->size = actualSize;
+ result = (void*)(newData + 1);
+ }
+
+#if PMEM_LOG_LOWLEVEL
+ if (gFile != NULL && isLogEnabled)
+ {
+#if PMEM_STACKTRACE
+ LCHAR stackTrace[P_MAX_STACKTRACE];
+ size_t len = P_MAX_STACKTRACE;
+ ESR_ReturnCode rc;
+
+ rc = getStackTrace(stackTrace, &len);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, "[%s:%d] getStackTrace failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ pfprintf(gFile, L("pmem|%s|%d|realloc|%d|0x%x|%s|\n"), e->tag, oldSize, actualSize, ptr, stackTrace);
+#else
+ pfprintf(gFile, L("pmem|%s|%d|realloc|%d|0x%x|\n"), e->tag, oldSize, actualSize, ptr);
+#endif /* PMEM_STACKTRACE */
+ }
+#endif /* PMEM_LOG_LOWLEVEL */
+
+ unlockMutex(&memMutex);
+ return result;
+#if PMEM_STACKTRACE && PMEM_LOG_LOWLEVEL
+CLEANUP:
+ unlockMutex(&memMutex);
+ return NULL;
+#endif
+}
+
+#ifdef PMEM_MAP_TRACE
+void pfree(void* ptr, const LCHAR* file, int line)
+#else
+void pfree(void* ptr)
+#endif
+{
+ MemoryData* data;
+#ifdef PMEM_MAP_TRACE
+ MemMapEntry* e;
+#endif
+ if (ptr == NULL || gNbInit == 0)
+ return;
+
+ lockMutex(&memMutex);
+
+ data = (MemoryData*)(((unsigned char*) ptr) - sizeof(MemoryData));
+#ifdef PMEM_MAP_TRACE
+ passert(data->index >= 0 && data->index <= MAX_MEM_TAG);
+ e = gMemoryMap + data->index;
+ if (isLogEnabled)
+ {
+ passert(e->curAlloc >= data->size);
+ e->curAlloc -= data->size;
+
+ passert(gCurAlloc >= data->size);
+ gCurAlloc -= data->size;
+ }
+#if PMEM_STACKTRACE
+ if (e->first != NULL && e->first == data)
+ e->first = data->next;
+ if (e->last != NULL && e->last == data)
+ e->last = data->last;
+ if (data->last != NULL)
+ data->last->next = data->next;
+ if (data->next != NULL)
+ {
+ data->next->last = data->last;
+ data->next = NULL;
+ }
+ data->last = NULL;
+#endif /* PMEM_STACKTRACE */
+#if PMEM_LOG_LOWLEVEL
+ if (gFile != NULL && isLogEnabled)
+ {
+#if PMEM_STACKTRACE
+ LCHAR stackTrace[P_MAX_STACKTRACE];
+ size_t len = P_MAX_STACKTRACE;
+ ESR_ReturnCode rc;
+
+ rc = getStackTrace(stackTrace, &len);
+ if (rc != ESR_SUCCESS)
+ {
+ pfprintf(PSTDERR, "[%s:%d] getStackTrace failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
+ goto CLEANUP;
+ }
+ pfprintf(gFile, L("pmem|free|%s|%s|%d|0x%x|%s|\n"), e->tag, data->stackTrace, data->size, ptr, stackTrace);
+#else
+ pfprintf(gFile, L("pmem|free|%s|%d|0x%x\n"), e->tag, data->size, ptr);
+#endif /* PMEM_STACKTRACE */
+ }
+#endif /* PMEM_LOG_LOWLEVEL */
+#if PMEM_STACKTRACE
+ free((LCHAR*) data->stackTrace);
+ data->stackTrace = NULL;
+#endif /* PMEM_STACKTRACE */
+#endif
+
+ free(data);
+ unlockMutex(&memMutex);
+#if PMEM_STACKTRACE && PMEM_LOG_LOWLEVEL
+CLEANUP:
+ unlockMutex(&memMutex);
+ return;
+#endif
+
+}
diff --git a/portable/src/pmemory_ext.c b/portable/src/pmemory_ext.c
new file mode 100644
index 0000000..a30a6cb
--- /dev/null
+++ b/portable/src/pmemory_ext.c
@@ -0,0 +1,369 @@
+/*---------------------------------------------------------------------------*
+ * pmemory_ext.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#include "pmemory.h"
+#include "ptrd.h"
+#include "pmutex.h"
+#include "passert.h"
+#include "pmemory_ext.h"
+#include "pmalloc.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
+ static MUTEX memextMutex;
+#endif
+
+#ifdef RTXC
+ void* operator new(size_t size)
+ {
+ return (PortNew(size));
+ }
+ void operator delete(void* ptr)
+ {
+ PortDelete(ptr);
+ }
+#endif
+
+#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
+
+ /* to assist with leak checking */
+static int portNewCount = 0;
+static int portDeleteCount = 0;
+
+ /* enable writing and checking of guard words if debugging is enabled */
+#ifdef _DEBUG
+ /* crash on Xanavi's board with this option on, do not know why */
+ /* #define DBG_GUARD_WORDS */
+#endif /* _DEBUG */
+
+ /* ************************************************************************************
+ * PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR || PORTABLE_DINKUM_MEM_MGR || PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME
+ * ************************************************************************************/
+
+ /* data ******************************************************************************/
+
+ static BOOL gMemoryInitted = FALSE; /* TODO: Temporary fix to PortTerm failure */
+
+#define MEM_MGR_GetPoolSize() PortMallocGetPoolSize()
+#define MEM_MGR_SetPoolSize(sizeInBytes) PortMallocSetPoolSize(sizeInBytes)
+#define MEM_MGR_Init() PortMallocInit()
+#define MEM_MGR_Term() PortMallocTerm()
+#define MEM_MGR_Allocate(sizeInBytes) PortMalloc(sizeInBytes)
+#define MEM_MGR_Free(objectPtr) PortFree(objectPtr)
+#define MEM_MGR_Dump()
+#define MEM_MGR_GetMaxMemUsed() PortMallocGetMaxMemUsed()
+
+ /* guard word data ********************************************************/
+
+#ifdef DBG_GUARD_WORDS
+#define GUARD_BEGIN 0xbbbbbbbb
+#define GUARD_END 0xeeeeeeee
+
+#define GUARD_OFF_REQ_SIZE 0
+#define GUARD_OFF_START sizeof(unsigned int)
+#define GUARD_OFF_PTR (sizeof(unsigned int) + sizeof(unsigned int))
+#define GUARD_EXTRA (sizeof(unsigned int) + sizeof(unsigned int) + sizeof(unsigned int))
+#define GUARD_OFF_END(allocSize) ((allocSize) - sizeof(unsigned int))
+#define GUARD_ALLOC_SIZE(reqSize) ((reqSize)+GUARD_EXTRA)
+
+#define GUARD_PTR_FIELD(ptr,off) (unsigned int *)((char *)(ptr) + (off))
+#define GUARD_ALLOC_PTR(ptr) (void*) ((char *)(ptr) - GUARD_OFF_PTR)
+#endif
+
+ /* scan guard words data **************************************************/
+
+ /* maintain a static list of allocated blocks (didn't want to perform any dynamic allocation).
+ * This list can be scanned by PortMemScan() to determine if any allocated blocks
+ * have overwritten their guard words.
+ * Calling PortDelete() will check guard words upon de-allocation, but many
+ * allocated blocks are only freed at program termination, which sometimes doesn't happen.
+ *
+ * This software is enabled separately with DBG_SCAN_GUARD_WORDS, because the performance
+ * overhead is severe.
+ */
+#ifdef DBG_SCAN_GUARD_WORDS
+#define MAX_ALLOCATED_BLOCKS 80000
+ static void *allocArray[MAX_ALLOCATED_BLOCKS+1];
+ static int allocArrayCount = 0;
+
+ void AddToAllocList(void *memPtr);
+ void RemoveFromAllocList(void *memPtr);
+
+#define ADD_TO_ALLOC_LIST(ptr) AddToAllocList(ptr)
+#define REMOVE_FROM_ALLOC_LIST(ptr) RemoveFromAllocList(ptr)
+
+#else
+#define ADD_TO_ALLOC_LIST(ptr)
+#define REMOVE_FROM_ALLOC_LIST(ptr)
+#endif
+
+ /* Guard Functions ********************************************************/
+
+#ifdef DBG_SCAN_GUARD_WORDS
+ /* AddToAllocList() : maintain an array of allocated blocks that can be
+ * used by PortMemScan() to check for overwritten guard words.
+ */
+ void AddToAllocList(void *memPtr)
+ {
+ allocArray[allocArrayCount] = memPtr;
+ allocArrayCount++;
+ if (allocArrayCount >= MAX_ALLOCATED_BLOCKS)
+ {
+ char buf[256];
+ sprintf(buf, "AddToAllocList ERROR : MAX_ALLOCATED_BLOCKS is too small (%d)", allocArrayCount);
+ PORT_INTERNAL_ERROR(buf);
+ }
+ }
+
+ /* RemoveFromAllocList() : maintain an array of allocated blocks that can be
+ * used by PortMemScan() to check for overwritten guard words.
+ */
+ void RemoveFromAllocList(void *memPtr)
+ {
+ int i; /* loop index */
+ int j; /* loop index */
+ int inList = FALSE; /* TRUE when found in list */
+
+ for (i = 0; i < allocArrayCount; i++)
+ {
+ if (allocArray[i] == memPtr)
+ {
+ inList = TRUE;
+ break;
+ }
+ }
+ PORT_ASSERT(inList == TRUE); /* MUST be in list */
+ /* remove by sliding down all following entries */
+ for (j = i + 1; j < allocArrayCount; j++)
+ allocArray[j-1] = allocArray[j];
+ allocArrayCount--;
+ allocArray[allocArrayCount] = NULL; /* clear out end of list */
+ }
+
+ /* PortMemScan() : scan the array of allocated blocks, confirming that no
+ * allocated block has overwritten its guard words.
+ */
+ void PortMemScan(void)
+ {
+ int i;
+
+ PortCriticalSectionEnter(&PortMemoryCriticalSection);
+
+ /* scan the allocated memory list */
+ for (i = 0; i < allocArrayCount; i++)
+ {
+ /* verify that guard words have not been corrupted */
+ void *memPtr = allocArray[i];
+ void *allocPtr = GUARD_ALLOC_PTR(memPtr);
+ unsigned int *requestedSizePtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE);
+ unsigned int *guardStartPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START);
+ unsigned int *guardEndPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr)));
+
+ if ((*guardStartPtr) != GUARD_BEGIN)
+ {
+ PLogError("PortMemScan : corrupted start guard from block 0x%08x \n", (int)memPtr);
+ }
+ if ((*guardEndPtr) != GUARD_END)
+ {
+ PLogError("PortMemScan : corrupted end guard from block 0x%08x \n", (int)memPtr);
+ }
+ }
+
+ PortCriticalSectionLeave(&PortMemoryCriticalSection);
+ }
+#endif /* DBG_SCAN_GUARD_WORDS */
+
+ /* Port Memory Functions ******************************************************/
+
+ /* PortMemGetPoolSize() : return size of portable memory pool, or 0 if
+ * unknown.
+ */
+ int PortMemGetPoolSize(void)
+ {
+ return MEM_MGR_GetPoolSize();
+ }
+
+ /* PortMemSetPoolSize() : set size of portable memory pool on PSOS.
+ * This must be called before PortMemoryInit(), which is called by PortInit().
+ */
+ void PortMemSetPoolSize(size_t sizeInBytes)
+ {
+ MEM_MGR_SetPoolSize(sizeInBytes);
+ }
+
+ /* PortMemoryInit() :
+ */
+
+ int PortMemoryInit(void)
+ {
+#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
+ if (createMutex(&memextMutex) == ESR_SUCCESS)
+#endif
+ {
+ if (!gMemoryInitted)
+ {
+ MEM_MGR_Init();
+ gMemoryInitted = TRUE;
+ }
+ }
+
+ return gMemoryInitted;
+ }
+
+ /* PortMemoryTerm() :
+ */
+
+ void PortMemoryTerm(void)
+ {
+ /* TODO: MEM_PSOS_BLOCK_SCHEME
+ * Figure out why free memory causes rn#0 is get messed up! */
+ MEM_MGR_Term();
+#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
+ deleteMutex(&memextMutex);
+#endif
+ gMemoryInitted = FALSE;
+ }
+
+ /* PortNew() :
+ */
+
+ void* PortNew(size_t sizeInBytes)
+ {
+ if (gMemoryInitted)
+ {
+ void *pMemory = NULL;
+
+#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
+ lockMutex(&memextMutex);
+#endif
+ portNewCount++;
+
+#ifdef DBG_GUARD_WORDS
+ sizeInBytes += GUARD_EXTRA; /* space for: requestedSize,guardStart,guardEnd */
+#endif
+
+ pMemory = MEM_MGR_Allocate(sizeInBytes);
+
+#ifdef DBG_GUARD_WORDS
+ if (NULL != pMemory)
+ {
+ /* at the beginning of the buffer, store the requested size and a guard word.
+ * Store another guard word at the end of the buffer.
+ */
+ /* set guard words at either end of allocated buffer; will be checked at delete time */
+ unsigned int * requestedSizePtr = GUARD_PTR_FIELD(pMemory, GUARD_OFF_REQ_SIZE);
+ unsigned int * guardStartPtr = GUARD_PTR_FIELD(pMemory, GUARD_OFF_START);
+ unsigned int * guardEndPtr = GUARD_PTR_FIELD(pMemory, GUARD_OFF_END(sizeInBytes));
+
+ *requestedSizePtr = sizeInBytes - GUARD_EXTRA;
+ *guardStartPtr = GUARD_BEGIN;
+ *guardEndPtr = GUARD_END;
+ pMemory = (void *) GUARD_PTR_FIELD(pMemory, GUARD_OFF_PTR);
+ ADD_TO_ALLOC_LIST(pMemory);
+ }
+#endif /* DBG_GUARD_WORDS */
+#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
+ unlockMutex(&memextMutex);
+#endif
+ return pMemory;
+ }
+#ifdef PSOSIM
+ /* PSOSIM's license manager calls new() before PSOS is running */
+ else
+ {
+ return(malloc(sizeInBytes));
+ }
+#else /* PSOSIM */
+ /* Memory allocator not initialized when request for memory was made */
+ passert(FALSE && "Call PortInit() before calling any portable functions\r\n");
+ return NULL;
+#endif /* PSOSIM */
+ }
+
+ void PortDelete(void* objectPtr)
+ {
+#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
+ lockMutex(&memextMutex);
+#endif
+ portDeleteCount++;
+
+#ifdef DBG_GUARD_WORDS
+ {
+ /* verify that guard words have not been corrupted */
+ void *allocPtr = GUARD_ALLOC_PTR(objectPtr);
+ unsigned int *requestedSizePtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE);
+ unsigned int *guardStartPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START);
+ unsigned int *guardEndPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr)));
+
+ passert((*guardStartPtr) == GUARD_BEGIN);
+ passert((*guardEndPtr) == GUARD_END);
+ REMOVE_FROM_ALLOC_LIST(allocPtr);
+ objectPtr = allocPtr;
+ }
+#endif
+
+ MEM_MGR_Free(objectPtr);
+#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
+ unlockMutex(&memextMutex);
+#endif
+ }
+
+ void PortMemTrackDump(void)
+ {
+ MEM_MGR_Dump();
+ }
+
+ /* PortGetMaxMemUsed() : return the maximum real memory allocated.
+ * There is another function of the same name in pmalloc.c, for tracking
+ * non-psos block memory. It uses #ifndef MEM_PSOS_BLOCK_SCHEME to enable.
+ */
+ int PortGetMaxMemUsed(void)
+ {
+ return MEM_MGR_GetMaxMemUsed();
+ }
+
+ /* PortMemCntReset() : reset the New/Delete count.
+ * This is useful for checking that each new has a corresponding delete once
+ * the system gets into a steady state.
+ */
+ void PortMemCntReset()
+ {
+ portNewCount = 0;
+ portDeleteCount = 0;
+ }
+
+
+ /* PortMemGetCount() : return the accumulated new & delete counts */
+ void PortMemGetCount(int *newCount, int *deleteCount)
+ {
+ *newCount = portNewCount;
+ *deleteCount = portDeleteCount;
+ }
+
+#endif /* (==PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR) || (==PORTABLE_DINKUM_MEM_MGR) || (==PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME) */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/portable/src/pmemory_ext.h b/portable/src/pmemory_ext.h
new file mode 100644
index 0000000..15db654
--- /dev/null
+++ b/portable/src/pmemory_ext.h
@@ -0,0 +1,47 @@
+/*---------------------------------------------------------------------------*
+ * pmemory_ext.h *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#ifndef _PORTMEMORY_EXT_H
+#define _PORTMEMORY_EXT_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /* TODO - removed PortNewAndTrace and PortDeleteAndTrace * Ian 06-March-2002 */
+
+ int PortMemoryInit(void);
+ void PortMemoryTerm(void);
+ void* PortNew(size_t sizeInBytes);
+ void PortDelete(void* objectPtr);
+ void PortMemTrackDump(void);
+ int PortGetMaxMemUsed(void);
+ int PortMemGetPoolSize(void);
+ void PortMemSetPoolSize(size_t sizeInBytes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PORTMEMORY_H */
diff --git a/portable/src/pstream.c b/portable/src/pstream.c
new file mode 100644
index 0000000..e75d403
--- /dev/null
+++ b/portable/src/pstream.c
@@ -0,0 +1,990 @@
+/*---------------------------------------------------------------------------*
+ * pstream.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <string.h>
+#include "passert.h"
+#include "pstdio.h"
+#include "pmemory.h"
+#include "plog.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef PFILE_VIRTUAL_SUPPORT
+
+#define FILETEXTMODE 0x00
+#define FILEBINARYMODE 0x01
+#define FILEREADMODE 0x00
+#define FILEWRITEMODE 0x02
+
+ /* Open a existed writable file (i.e., the file is not closed yet).
+ At some cases user knows the filename only but does not know the file handle (1),
+ the user could call fopen to open this file again with another file handle (2).
+ He/She could get all the information before the last fflush was called via file handle (1).
+ */
+#define FILEREOPENMODE 0x08
+
+#define ISWRITEMODE(mode) (((mode)&FILEWRITEMODE) == FILEWRITEMODE)
+
+#define ISBINARYMODE(mode) (((mode)&FILEBINARYMODE) == FILEBINARYMODE)
+#define ISREOPENMODE(mode) (((mode)&FILEREOPENMODE) == FILEREOPENMODE)
+
+ /*
+ use a double link list to store the data of the writable file.
+ Each entry has 4k space (FILEBUFFERSIZE).
+ */
+#define FILEBUFFERSIZE 4096 /* 4k for each file buffer entry */
+
+ typedef struct FileBufferFrame
+ {
+ unsigned char *buffer; /* do not use pointer here and set it the first */
+ size_t size;
+ size_t index; /* nth buffer, from 0, 1, ... */
+ struct FileBufferFrame *prev;
+ struct FileBufferFrame *next;
+ BOOL bMalloc; /* flag, if the buffer malloced here ? */
+ }
+ FileBufferFrame;
+
+ FileRecord pWritableFileRecTable[] =
+ {
+ {"", 0, 0, 0, 3},
+ {"", 0, 0, 0, 3},
+ {"", 0, 0, 0, 3},
+ {"", 0, 0, 0, 3},
+ {"", 0, 0, 0, 3},
+ {"", 0, 0, 0, 3},
+ {"", 0, 0, 0, 3}
+ };
+ const nWritableFiles = sizeof(pWritableFileRecTable) / sizeof(pWritableFileRecTable[0]);
+
+#ifdef WIN32
+ extern const FileRecord pFileRecTable[];
+ extern const unsigned char pFileStart0[];
+#endif
+
+ const FileRecord *pReadOnlyFileRecTable = NULL;
+ const unsigned char *g_pFirstFile = NULL;
+
+ void SetFileTable(VirtualFileTable *table)
+ {
+#ifdef WIN32
+ pReadOnlyFileRecTable = pFileRecTable;
+ g_pFirstFile = pFileStart0;
+#else
+ if (table)
+ {
+ pReadOnlyFileRecTable = table->pFileTable;
+ g_pFirstFile = table->pFirstFile;
+ }
+#endif
+ }
+
+ /*
+ size: size of buffer.
+ buffer: is NULL, allocate here and set bMalloc as TRUE; otherwise use the external buffer
+ */
+ FileBufferFrame* CreateFileBufferFrame(size_t size, unsigned char *buffer)
+ {
+ FileBufferFrame *fb = NULL;
+
+ /* create FileBufferFrame */
+ fb = (FileBufferFrame *)MALLOC(sizeof(FileBufferFrame), "FileBufferFrame");
+ if (fb)
+ {
+ fb->next = NULL;
+ fb->prev = NULL;
+ fb->index = 0;
+ fb->size = size;
+ fb->bMalloc = FALSE;
+
+ if (buffer)
+ fb->buffer = buffer;
+ else
+ {
+ /* create one buffer frame */
+ if ((fb->buffer = (unsigned char *)MALLOC(size, "FileBufferFrame Buffer")) == NULL)
+ {
+ FREE(fb);
+ return NULL;
+ }
+ fb->bMalloc = TRUE;
+ }
+ }
+ return fb;
+ }
+
+ /* free FileBufferFrames
+ header should be the header of the FileBufferFrame link list
+ */
+ void DeleteFileBuffers(FileBufferFrame *header)
+ {
+ FileBufferFrame *next, *curr;
+
+ passert(header && header->prev == NULL); /* delete from the beginning */
+
+ curr = header;
+ do
+ {
+ next = curr->next;
+ if (curr->bMalloc)
+ FREE(curr->buffer);
+ FREE(curr);
+ curr = next;
+ }
+ while (next != NULL);
+ }
+
+ void PortFileInit(void)
+ {
+ /* No gPortStdin, gPortStdout, and gPortStderr to initialize. */
+#ifdef WIN32
+ pReadOnlyFileRecTable = pFileRecTable;
+ g_pFirstFile = pFileStart0;
+#endif
+ }
+
+ /* Assume that all files have at least one byte in them, that is length is > 0. */
+ PORT_FILE PortFopen(const char *filename, const char *mode)
+ {
+ char *pfn;
+ const unsigned char *start;
+ int size;
+ int text_mode;
+ int access_mode;
+ int m = 0;
+ PORT_FILE PortFile;
+ FileBufferFrame *curFrame;
+ size_t end;
+
+ passert(filename);
+ passert(mode);
+
+ if (pReadOnlyFileRecTable == NULL)
+ {
+ passert("File Table is not initialized!" == NULL);
+ return NULL;
+ }
+
+ /* support read and write. */
+ if (mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'R') /* w means w+, attaching text */
+ {
+ char fname[80];
+ FileRecord *pCurRec;
+
+ access_mode = (mode[0] == 'r') ? FILEREADMODE : FILEWRITEMODE;
+
+ /* access mode: b/t */
+ if (mode[1] == '+')
+ text_mode = (mode[2] == 'b') ? FILEBINARYMODE : FILETEXTMODE;
+ else
+ text_mode = (mode[1] == 'b') ? FILEBINARYMODE : FILETEXTMODE;
+
+ /* Remove the directory path from the filename. */
+ if ((pfn = strrchr(filename, '/')) != NULL || (pfn = strrchr(filename, '\\')) != NULL)
+ strcpy(fname, pfn + 1);
+ else
+ strcpy(fname, filename);
+
+
+ /* Locate the start of the file, by looking through the file record table. */
+ if (access_mode == FILEREADMODE)
+ {
+ pCurRec = (FileRecord *)pReadOnlyFileRecTable;
+ start = g_pFirstFile;
+ }
+ else
+ {
+ pCurRec = (FileRecord *)pWritableFileRecTable;
+ }
+
+ while (pCurRec->size > 0 && strcmp(pCurRec->name, fname) != 0)
+ {
+ /* have to count the read-only file address in order to be best portable */
+ start += pCurRec->size;
+ pCurRec++;
+#ifndef NDEBUG
+ /* just for our internal test for read-only files.
+ if (pCurRec->start != NULL)
+ passert(start == pCurRec->start);
+ */
+#endif
+ }
+
+ m = access_mode | text_mode;
+ /* Do not support reopen the writable file now. */
+ if (access_mode == FILEREADMODE)
+ {
+ if (pCurRec->size == 0)
+ {
+ return NULL;
+ }
+
+ /* Found the file, record it's starting offset and length. */
+ end = pCurRec->end;
+ size = pCurRec->size;
+ }
+ /* writable file, open it the first time; could be text or binary */
+ else if (ISWRITEMODE(access_mode))
+ {
+ /* set the name and mode */
+ strcpy(pCurRec->name, fname);
+ pCurRec->mode = m;
+
+ start = pCurRec->start;
+ passert(start == NULL);
+ end = size = FILEBUFFERSIZE;
+ }
+ else
+ {
+ /* File doesn't exist. */
+ return NULL;
+ }
+ pfn = pCurRec->name;
+ }
+ else
+ {
+ /* Unknown mode */
+ return NULL;
+ }
+
+ /* Open file */
+ /* Create new file handle */
+ PortFile = (PORT_FILE)MALLOC(sizeof(PORT_FILE_HANDLE), "PortFile");
+ if (PortFile == NULL)
+ {
+ return NULL;
+ }
+
+ /* this mode is not tested yet */
+ if (ISREOPENMODE(m))
+ {
+ PortFile->startFrame = (FileBufferFrame *)start;
+ }
+ else
+ {
+ PortFile->startFrame = CreateFileBufferFrame(size, (unsigned char *)start);
+ if (ISWRITEMODE(m))
+ {
+ start = (const unsigned char *)PortFile->startFrame;
+ }
+ }
+
+ if (PortFile->startFrame == NULL)
+ {
+ FREE(PortFile);
+ return NULL;
+ }
+
+ PortFile->endFrame = PortFile->curFrame = PortFile->startFrame;
+
+ /* Mark that this file handle is for flash memory */
+ PortFile->filename = pfn;
+ PortFile->curPos = PortFile->curFrame->buffer;
+ PortFile->endPos = PortFile->curPos + end;
+
+ /* set the PortFile->endPos */
+ curFrame = PortFile->curFrame;
+ while (end > 0)
+ {
+ if (end > curFrame->size)
+ {
+ curFrame = curFrame->next;
+ passert(end > curFrame->size);
+ end -= curFrame->size;
+ passert(curFrame);
+ }
+ else
+ {
+ /* only reopen the writable file comes here */
+ PortFile->endPos = curFrame->buffer + end;
+ break;
+ }
+ }
+
+ PortFile->eof = 0; /* File must have at least one byte in it. */
+ PortFile->size = size;
+ PortFile->mode = m;
+
+ return PortFile;
+ }
+
+ int PortFclose(PORT_FILE PortFile)
+ {
+ passert(PortFile);
+
+ /* for reopen mode, do not delete the FileBufferFrame. Delete it by who created it */
+ if (ISWRITEMODE(PortFile->mode) && !ISREOPENMODE(PortFile->mode)) /* writable file */
+ {
+ int i = 0;
+ FileRecord *pCurRec = (FileRecord *)pWritableFileRecTable;
+
+ /* find the file record in memory */
+ for (i = 0; i < nWritableFiles; i++)
+ {
+ if (PortFile->size > 0 &&
+ PortFile->filename[0] != '\0' &&
+ strcmp(pCurRec->name, PortFile->filename) == 0
+ )
+ {
+ /* The parameter SREC.Recognizer.osi_log_level in par file control the output
+ # BIT 0 -> BASIC logging
+ # BIT 1 -> AUDIO waveform logging
+ # BIT 2 -> ADD WORD logging
+ # e.g. value is 3 = BASIC+AUDIO logging, no ADDWORD
+ SREC.Recognizer.osi_log_level = 7;
+
+ Do not control here
+ */
+ /*
+ SaveFileToDisk(PortFile);
+ */
+
+ pCurRec->name[0] = '\0';
+ pCurRec->start = NULL;
+ pCurRec->end = 0;
+ pCurRec->size = 0;
+
+ break;
+ }
+ pCurRec++;
+ }
+ }
+
+ DeleteFileBuffers(PortFile->startFrame);
+ FREE(PortFile);
+ return 0;
+ }
+
+ /*
+ * Returns the number of items read
+ */
+ size_t PortFread(void *buffer, size_t size, size_t count, PORT_FILE PortFile)
+ {
+ unsigned char *bufferPtr = (unsigned char *)buffer;
+ int cbRemain = size * count;
+ int cbAvail, minSize;
+ FileBufferFrame *curFrame = PortFile->curFrame;
+
+ passert(buffer);
+ passert(PortFile);
+
+ if (PortFile->eof == 1)
+ {
+ return 0;
+ }
+
+ while (cbRemain > 0)
+ {
+ if (PortFile->endPos == PortFile->curPos) /* end of file */
+ break;
+
+ if (PortFile->curPos == curFrame->buffer + curFrame->size) /* end of this frame */
+ {
+ /* go to next frame */
+ curFrame = PortFile->curFrame = curFrame->next;
+ PortFile->curPos = curFrame->buffer;
+ }
+
+ if (curFrame == PortFile->endFrame) /* last frame */
+ cbAvail = PortFile->endPos - PortFile->curPos;
+ else
+ cbAvail = curFrame->size - (PortFile->curPos - curFrame->buffer);
+
+ minSize = cbRemain < cbAvail ? cbRemain : cbAvail;
+ passert(minSize >= 0);
+
+ cbRemain -= minSize;
+ while (minSize-- > 0)
+ *bufferPtr++ = *PortFile->curPos++;
+ }
+
+ if (PortFile->curPos == PortFile->endPos)
+ {
+ PortFile->eof = 1;
+ }
+ /*
+ #ifdef __BIG_ENDIAN
+ if (!bNativeEnding)
+ {
+ swap_byte_order((char *)buffer, count, size);
+ }
+ #endif
+ */
+ return count - cbRemain / size;
+ }
+
+ /*
+ * Returns the number of items written
+ */
+ size_t PortFwrite(const void *data, size_t size, size_t count, PORT_FILE PortFile)
+ {
+ int cbWrite = size * count;
+ int cbAvail, minSize;
+ unsigned char *buffer = (unsigned char *)data;
+ FileBufferFrame *curFrame;
+
+ if (PortFile == NULL)
+ return 0;
+
+ curFrame = PortFile->curFrame;
+
+ /* write data until the end of the internal buffer */
+ if (PortFile->eof == 1)
+ {
+ /* TODO: should return 0, but it will cause infinite loop */
+ return 0;
+ }
+
+ /* why sub 1 ? */
+ while (cbWrite > 0)
+ {
+ if (PortFile->curPos == curFrame->buffer + curFrame->size) /* end of this frame */
+ {
+ if (curFrame->next == NULL)
+ {
+ /* assign a new space */
+ FileBufferFrame *nextFrame = CreateFileBufferFrame(FILEBUFFERSIZE, NULL);
+ if (nextFrame)
+ {
+ curFrame->next = nextFrame;
+ nextFrame->prev = curFrame;
+ nextFrame->index = curFrame->index + 1;
+
+ curFrame = PortFile->curFrame = nextFrame;
+ PortFile->endFrame = nextFrame;
+ PortFile->curPos = PortFile->endPos = nextFrame->buffer;
+
+ PortFile->size += FILEBUFFERSIZE;
+ }
+ else
+ {
+ return count -cbWrite / size;
+ }
+ }
+ else
+ curFrame = curFrame->next;
+ }
+
+ /* available space in current frame */
+ cbAvail = curFrame->size - (PortFile->curPos - curFrame->buffer);
+ minSize = cbWrite < cbAvail ? cbWrite : cbAvail;
+
+ memcpy((char *)PortFile->curPos, buffer, minSize);
+ buffer += minSize;
+ PortFile->curPos += minSize;
+ /* in case the write is not adding to the end */
+ if (curFrame == PortFile->endFrame && PortFile->endPos < PortFile->curPos)
+ PortFile->endPos = PortFile->curPos;
+ cbWrite -= minSize;
+ }
+
+ return count;
+ }
+
+ /*
+ * Returns 0 on success, non-zero on failure
+ */
+ int PortFseek(PORT_FILE PortFile, long offset, int origin)
+ {
+ int retval = 0;
+ int cbAvail, minSize;
+ FileBufferFrame *curFrame;
+
+ passert(PortFile);
+
+ /* Clear eof flag */
+ PortFile->eof = 0;
+
+ switch (origin)
+ {
+ case SEEK_CUR:
+ break;
+ case SEEK_END:
+ PortFile->curFrame = PortFile->endFrame;
+ PortFile->curPos = PortFile->endPos;
+ break;
+ case SEEK_SET:
+ PortFile->curFrame = PortFile->startFrame;
+ PortFile->curPos = PortFile->startFrame->buffer;
+ break;
+ default:
+ retval = 0; /* Error, unknown origin type */
+ break;
+ }
+
+ curFrame = PortFile->curFrame;
+
+ while (offset != 0)
+ {
+ if (offset > 0)
+ {
+ if (PortFile->endPos <= PortFile->curPos) /* end of file */
+ break;
+
+ if (PortFile->curPos == curFrame->buffer + curFrame->size) /* end of this frame */
+ {
+ /* go to next frame */
+ curFrame = curFrame->next;
+ if (curFrame == NULL)
+ break;
+ PortFile->curFrame = curFrame->next;
+ PortFile->curPos = curFrame->buffer;
+ }
+ if (curFrame == PortFile->endFrame) /* last frame */
+ cbAvail = PortFile->endPos - PortFile->curPos;
+ else
+ cbAvail = curFrame->size - (PortFile->curPos - curFrame->buffer);
+
+ minSize = offset < cbAvail ? offset : cbAvail;
+
+ PortFile->curPos += minSize;
+ offset -= minSize;
+ }
+ else
+ {
+ if (PortFile->startFrame->buffer == PortFile->curPos) /* start of file */
+ break;
+
+ if (PortFile->curPos <= curFrame->buffer) /* start of this frame */
+ {
+ /* go to next frame */
+ curFrame = curFrame->next;
+ if (curFrame == NULL)
+ break;
+ PortFile->curFrame = curFrame;
+ PortFile->curPos = curFrame->buffer + curFrame->size;
+ }
+ cbAvail = PortFile->curPos - curFrame->buffer;
+
+ minSize = -offset < cbAvail ? -offset : cbAvail;
+
+ PortFile->curPos -= minSize;
+ offset += minSize;
+ }
+ }
+ return retval;
+ }
+
+ /*
+ * Returns current file position
+ */
+ long PortFtell(PORT_FILE PortFile)
+ {
+ int size;
+ FileBufferFrame *curFrame = PortFile->curFrame;
+
+ passert(PortFile);
+
+ /* current Frame size */
+ size = PortFile->curPos - curFrame->buffer;
+
+ /* previous frame size */
+ while (curFrame = curFrame->prev)
+ size += curFrame->size;
+
+ return size;
+ }
+
+ int PortVfprintf(PORT_FILE PortFile, const char *format, va_list argptr)
+ {
+ char message[2*2048] = "";
+
+ /* Print formatted message to buffer */
+ vsprintf(message, format, argptr);
+
+ if (PortFile == NULL)
+ {
+ /* TODO: HECK to screen */
+#ifndef NDEBUG
+ printf(message);
+#endif
+ return 0;
+ }
+
+ passert(strlen(message) < 2*2048);
+ /* TO DO, seems at case fprintf(pf, "whatever"), message is empty! */
+ if (strlen(message) == 0)
+ return 0;
+ else
+ return PortFwrite(message, sizeof(char), strlen(message), PortFile);
+ }
+
+ /*
+ * Returns current file position
+ */
+ int PortFprintf(PORT_FILE PortFile, const char* format, ...)
+ {
+ va_list log_va_list;
+ int ret = 0;
+
+ /* Start variable argument list */
+ va_start(log_va_list, format);
+
+ /* Print formatted message to buffer */
+ ret = PortVfprintf(PortFile, format, log_va_list);
+
+ /* End variable argument list */
+ va_end(log_va_list);
+
+ return ret;
+ }
+
+ /*
+ * Returns string or NULL if error
+ */
+ char *PortFgets(char *string, int n, PORT_FILE PortFile)
+ {
+ int cbToRead = n - 1;
+ BOOL done = FALSE;
+ char *retString = NULL;
+ int i;
+
+ passert(string);
+ passert(n);
+ passert(PortFile);
+
+
+ if (PortFile->eof == 1)
+ {
+ return NULL;
+ }
+
+
+ /* Search for \n only! */
+ for (i = 0; i < cbToRead && !done; i++)
+ {
+ if (PortFile->curPos >= PortFile->endPos)
+ {
+ PortFile->eof = 1;
+ done = TRUE;
+ break;
+ }
+ else if (*PortFile->curPos == '\n')
+ {
+ if (retString == NULL)
+ {
+ retString = string;
+ }
+ retString[i] = '\n';
+ PortFile->curPos++;
+ done = TRUE;
+ }
+ else
+ {
+ if (retString == NULL)
+ {
+ retString = string;
+ }
+ retString[i] = *PortFile->curPos++;
+ }
+ }
+ if (retString != NULL)
+ {
+ retString[i] = '\0';
+ }
+ return retString;
+ }
+
+ /*
+ * Returns string or NULL if error
+ */
+ int PortFflush(PORT_FILE PortFile)
+ {
+ if (PortFile == NULL)
+ {
+ return -1;
+ }
+
+
+ /* call fflush before reopen a writable file */
+ if (ISWRITEMODE(PortFile->mode)) /* writable file */
+ {
+ FileRecord *pCurRec = (FileRecord *)pWritableFileRecTable;
+
+ /* find the file record in memory */
+ do
+ {
+ if (strcmp(pCurRec->name, PortFile->filename) == 0)
+ {
+ /* assgin it as startFrame, so others could get information when reopen it */
+ pCurRec->start = (unsigned char *)PortFile->startFrame;
+ pCurRec->end = PortFile->size - PortFile->endFrame->size +
+ (PortFile->endPos - PortFile->endFrame->buffer);
+ pCurRec->size = PortFile->size;
+ pCurRec->mode = PortFile->mode;
+
+ break;
+ }
+ pCurRec++;
+ }
+ while (pCurRec->size > 0);
+ }
+ return 0;
+ }
+
+
+ int PortFeof(PORT_FILE PortFile)
+ {
+ passert(PortFile);
+
+ return PortFile->eof;
+ }
+
+ /*
+ * Returns character or EOF
+ */
+ int PortFgetc(PORT_FILE PortFile)
+ {
+ int c;
+
+ passert(PortFile);
+
+ if (PortFile->eof == 1)
+ {
+ return EOF;
+ }
+ else
+ {
+ c = (int) * PortFile->curPos++;
+
+ if (PortFile->curPos >= PortFile->endPos)
+ {
+ PortFile->eof = 1;
+ }
+ }
+ return c;
+ }
+
+ /*
+ * Returns 0 if no error
+ */
+ int PortFerror(PORT_FILE PortFile)
+ {
+ passert(PortFile);
+
+ return 0;
+ }
+
+ void PortClearerr(PORT_FILE PortFile)
+ {
+ PortFile->eof = 0;
+ }
+
+ /*
+ * Returns current file position
+ */
+ int PortFscanf(PORT_FILE PortFile, const char* format, ...)
+ {
+ passert(PortFile);
+
+ (void)format;
+
+ /* Not supported. */
+ passert(FALSE);
+ return 0;
+ }
+
+ void PortRewind(PORT_FILE PortFile)
+ {
+ passert(PortFile);
+
+ PortFile->curFrame = PortFile->startFrame;
+ PortFile->curPos = PortFile->startFrame->buffer;
+
+ PortFile->eof = 0;
+ }
+
+ /*
+ * NULL if it fails, otherwise a valid file pointer
+ */
+ PORT_FILE PortFreopen(const char *path, const char *mode, PORT_FILE PortFile)
+ {
+ /* does not support reopen writable file */
+ if (PortFclose(PortFile) == 0)
+ {
+ PortFile = PortFopen(path, mode);
+ return PortFile;
+ }
+ return NULL;
+ }
+
+ char* PortGetcwd(char *buffer, int maxlen)
+ {
+ if (maxlen >= 1)
+ buffer[0] = '\0';
+ else
+ return NULL;
+
+ return buffer;
+ }
+
+ int PortMkdir(const char *dirname)
+ {
+ return 0;
+ }
+
+#ifdef XANAVI_PROJECT
+
+ int PortSaveFileToDisk(PORT_FILE PortFile, const char *path, const char *fname)
+ {
+ /* ### start mod */
+
+ FILE *fp = NULL; /* real file handle */
+ char fullfname[256], data[256];
+ char mode[3];
+ const char *file;
+ int size;
+
+ if (fname == NULL)
+ file = PortFile->filename;
+ else
+ file = fname;
+
+ if (path == NULL)
+ {
+ PLogMessage("trying to save file %s...\n", file);
+ sprintf(fullfname, "%s", file);
+ }
+ else
+ {
+ PLogMessage("trying to save file %s to %s...\n", file, path);
+ sprintf(fullfname, "%s/%s", path, file);
+ }
+
+ if (ISBINARYMODE(PortFile->mode)) /* binary file, the wav file */
+ {
+ sprintf(mode, "wb");
+ }
+ else
+ {
+ sprintf(mode, "w");
+ }
+
+ if ((fp = fopen(fullfname, mode)) != NULL)
+ {
+ PortRewind(PortFile);
+
+ while ((size = PortFread(data, 1, 256, PortFile)) > 0)
+ {
+ fwrite(data, 1, size, fp);
+ }
+ fclose(fp);
+ }
+ else
+ {
+ PLogError(L("Error to fopen %s with mode %s\n\n"), fullfname, mode);
+ return -1;
+ }
+ return 0;
+ }
+
+ int PortLoadFileFromDisk(PORT_FILE PortFile, const char *filename, const char *mode)
+ {
+ FILE *fp;
+ int size;
+ char data[256];
+
+ passert(PortFile);
+
+ if (filename == NULL)
+ filename = PortFile->filename;
+
+ if (mode == NULL)
+ {
+ data[0] = 'r';
+ if (ISBINARYMODE(PortFile->mode))
+ data[1] = 'b';
+ else
+ data[1] = '\0';
+ data[2] = '\0';
+ mode = data;
+ }
+
+ fp = fopen(filename, mode);
+
+ if (fp == NULL) /* do not have the file, it is fine */
+ return 0;
+
+ while ((size = fread(data, 1, 256, fp)) > 0)
+ PortFwrite(data, 1, size, PortFile);
+
+ fclose(fp);
+ /* go to the beginning of the file */
+ PortFseek(PortFile, 0, SEEK_SET);
+
+ return 0;
+ }
+
+ int XanaviSaveFileToDisk(PORT_FILE PortFile)
+ {
+ const char *tail;
+ int lenny;
+
+ passert(PortFile);
+
+ /* UG has to be 8.3 format! */
+ lenny = strlen(PortFile->filename);
+ if (lenny > 10)
+ tail = PortFile->filename + (lenny - 11);
+ else
+ tail = PortFile->filename;
+ /* printf( "8.3 filename is %s.\n", tail ); */
+
+ /* the 8.3 format has truncated the path in PortFile->filename,
+ should get the direcotry from par file
+ cmdline.DataCaptureDirectory = /CFC
+ TODO: here use /CFC directly to save time
+ */
+ return PortSaveFileToDisk(PortFile, "/CFC", tail);
+ }
+
+ int XanaviLoadFileFromDisk(PORT_FILE PortFile)
+ {
+ char fname[256];
+ char mode[3];
+
+ passert(PortFile);
+
+ sprintf(fname, "/CFC/%s", PortFile->filename);
+
+ mode[0] = 'r';
+ if (ISBINARYMODE(PortFile->mode))
+ mode[1] = 'b';
+ else
+ mode[1] = '\0';
+
+ mode[2] = '\0';
+
+ return PortLoadFileFromDisk(PortFile, fname, mode);
+ }
+
+#endif
+#endif /* STATIC_FILE_SYSTME */
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/portable/src/ptimer.c b/portable/src/ptimer.c
new file mode 100644
index 0000000..8cb72b9
--- /dev/null
+++ b/portable/src/ptimer.c
@@ -0,0 +1,264 @@
+/*---------------------------------------------------------------------------*
+ * ptimer.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+
+
+#include "pmemory.h"
+#include "ptimer.h"
+#include "pmutex.h"
+
+#ifdef _WIN32
+
+/*
+ Note that this implementation assumes that QueryPerformanceCounter is
+ available (requires NT 3.1 and above) and that 64 bit arithmetic is
+ available (requires VC)
+*/
+
+struct PTimer_t
+{
+ LARGE_INTEGER PerformanceFreq;
+ LARGE_INTEGER RefTime;
+ LARGE_INTEGER elapsed;
+};
+
+
+
+/**
+ * Creates a new timer object.
+ **/
+ESR_ReturnCode PTimerCreate(PTimer **timer)
+{
+ PTimer *tmp = NULL;
+
+ if (timer == NULL)
+ return ESR_INVALID_ARGUMENT;
+ tmp = NEW(PTimer, "PTimer");
+ if (tmp == NULL)
+ return ESR_OUT_OF_MEMORY;
+
+ if (QueryPerformanceFrequency(&tmp->PerformanceFreq) == 0)
+ {
+ FREE(tmp);
+ return ESR_NOT_SUPPORTED;
+ }
+ tmp->PerformanceFreq.QuadPart /= 1000;
+
+ tmp->RefTime.QuadPart = 0;
+ tmp->elapsed.QuadPart = 0;
+ *timer = tmp;
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PTimerDestroy(PTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ FREE(timer);
+ return ESR_SUCCESS;
+}
+
+/**
+ * Starts the timer. This sets the reference time from which all new elapsed
+ * time are computed. This does not reset the elapsed time to 0. This is
+ * useful to pause the timer.
+ **/
+ESR_ReturnCode PTimerStart(PTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ return (QueryPerformanceCounter(&timer->RefTime) ?
+ ESR_SUCCESS :
+ ESR_NOT_SUPPORTED);
+}
+
+/**
+ * Stops the timer.
+ **/
+ESR_ReturnCode PTimerStop(PTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ if (timer->RefTime.QuadPart != 0)
+ {
+ LARGE_INTEGER now;
+ if (!QueryPerformanceCounter(&now)) return ESR_NOT_SUPPORTED;
+ timer->elapsed.QuadPart += now.QuadPart - timer->RefTime.QuadPart;
+ timer->RefTime.QuadPart = 0;
+ }
+ return ESR_SUCCESS;
+}
+
+/**
+ * Returns the timer elapsed time. If the Timer is in the stopped state,
+ * successive calls to getElapsed() will always return the same value. If
+ * the Timer is in the started state, successive calls will return the
+ * elapsed time since the last time PTimerStart() was called.
+ */
+ESR_ReturnCode PTimerGetElapsed(PTimer *timer, asr_uint32_t* elapsed)
+{
+ if (timer == NULL || elapsed == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ if (timer->RefTime.QuadPart != 0)
+ {
+ LARGE_INTEGER now;
+ if (!QueryPerformanceCounter(&now)) return ESR_NOT_SUPPORTED;
+ *elapsed = (asr_uint32_t) ((timer->elapsed.QuadPart + (now.QuadPart - timer->RefTime.QuadPart))
+ / timer->PerformanceFreq.QuadPart);
+ }
+ else
+ *elapsed = (asr_uint32_t) (timer->elapsed.QuadPart / timer->PerformanceFreq.QuadPart);
+
+ return ESR_SUCCESS;
+}
+
+
+/**
+ * Resets the elapsed time to 0 and resets the reference time of the Timer.
+ * This effectively reset the timer in the same state it was right after creation.
+ **/
+ESR_ReturnCode PTimerReset(PTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ timer->RefTime.QuadPart = 0;
+ timer->elapsed.QuadPart = 0;
+ return ESR_SUCCESS;
+}
+
+#elif defined(POSIX)
+#include "ptrd.h"
+/*
+POSIX has a timer
+*/
+/* Clocks and timers: clock_settime, clock_gettime, clock_getres, timer_xxx and nanosleep */
+#ifndef _POSIX_TIMERS
+#ifndef __vxworks /* __vxworks does not define it! */
+#error "Timer is not defined!"
+#endif /* __vxworks */
+#endif /* _POSIX_TIMERS */
+
+#define TIMER_MAX_VAL 10000
+
+struct PTimer_t
+{
+ timer_t timer;
+ asr_uint32_t elapsed;
+};
+
+/**
+* Creates a new timer object.
+**/
+ESR_ReturnCode PTimerCreate(PTimer **timer)
+{
+ PTimer *tmp = NULL;
+
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ tmp = NEW(PTimer, "PTimer");
+ if (tmp == NULL) return ESR_OUT_OF_MEMORY;
+
+ *timer = tmp;
+ if (timer_create(CLOCK_REALTIME, NULL, &(tmp->timer)) < 0)
+ return ESR_NOT_SUPPORTED;
+
+ return ESR_SUCCESS;
+}
+
+ESR_ReturnCode PTimerDestroy(PTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ timer_delete(timer->timer);
+ FREE(timer);
+
+ return ESR_SUCCESS;
+}
+
+/**
+* Starts the timer. This sets the reference time from which all new elapsed
+* time are computed. This does not reset the elapsed time to 0. This is
+* useful to pause the timer.
+**/
+ESR_ReturnCode PTimerStart(PTimer *timer)
+{
+ struct itimerspec expire_time;
+
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+
+ expire_time.it_value.tv_sec = TIMER_MAX_VAL; /* set a large time for the timer */
+ expire_time.it_value.tv_nsec = 0;
+ return (timer_settime(timer->timer, 0, &expire_time, NULL) == 0 ?
+ ESR_SUCCESS :
+ ESR_NOT_SUPPORTED);
+}
+
+/**
+* Stops the timer.
+**/
+ESR_ReturnCode PTimerStop(PTimer *timer)
+{
+ struct itimerspec remaining;
+
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+
+ if (timer_gettime(timer->timer, &remaining) != 0) return ESR_NOT_SUPPORTED;
+#if defined(__vxworks)
+ timer_cancel(timer->timer);
+#endif
+ timer->elapsed = (asr_uint32_t) ((TIMER_MAX_VAL - remaining.it_value.tv_sec) * SECOND2MSECOND
+ - remaining.it_value.tv_nsec / MSECOND2NSECOND);
+
+ return ESR_SUCCESS;
+}
+
+/**
+* Returns the timer elapsed time. If the Timer is in the stopped state,
+* successive calls to getElapsed() will always return the same value. If
+* the Timer is in the started state, successive calls will return the
+* elapsed time since the last time PTimerStart() was called.
+*/
+ESR_ReturnCode PTimerGetElapsed(PTimer *timer, asr_uint32_t* elapsed)
+{
+ if (timer == NULL || elapsed == NULL)
+ return ESR_INVALID_ARGUMENT;
+
+ if (timer->elapsed == 0) /* stop is not called */
+ {
+ struct itimerspec remaining;
+ if (timer_gettime(timer->timer, &remaining) != 0) return ESR_NOT_SUPPORTED;
+ *elapsed = (asr_uint32_t) ((TIMER_MAX_VAL - remaining.it_value.tv_sec) * SECOND2MSECOND
+ - remaining.it_value.tv_nsec / MSECOND2NSECOND);
+ }
+ else
+ *elapsed = timer->elapsed;
+
+ return ESR_SUCCESS;
+}
+
+
+/**
+* Resets the elapsed time to 0 and resets the reference time of the Timer.
+* This effectively reset the timer in the same state it was right after creation.
+**/
+ESR_ReturnCode PTimerReset(PTimer *timer)
+{
+ if (timer == NULL) return ESR_INVALID_ARGUMENT;
+ timer->elapsed = 0;
+ return ESR_SUCCESS;
+}
+
+#else
+#error "Ptimer not implemented for this platform."
+#endif
diff --git a/portable/src/ptimestamp.c b/portable/src/ptimestamp.c
new file mode 100644
index 0000000..6211c31
--- /dev/null
+++ b/portable/src/ptimestamp.c
@@ -0,0 +1,56 @@
+/*---------------------------------------------------------------------------*
+ * ptimestamp.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "ptimestamp.h"
+#include "pmutex.h"
+
+#ifdef _WIN32
+#include "sys/timeb.h"
+#endif
+
+void PTimeStampSet(PTimeStamp *timestamp)
+{
+
+#ifdef DISABLE_TIMESTAMPS
+ timestamp->secs = 0;
+ timestamp->msecs = 0;
+#else
+
+#ifdef _WIN32
+ struct _timeb now;
+
+ _ftime(&now);
+ timestamp->secs = now.time;
+ timestamp->msecs = now.millitm;
+#elif defined(POSIX)
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+ timestamp->secs = now.tv_sec;
+ timestamp->msecs = now.tv_nsec / MSECOND2NSECOND;
+#else
+#error "PTimeStampSet not defined for this platform."
+#endif
+
+#endif
+}
+
+PINLINE int PTimeStampDiff(const PTimeStamp *a, const PTimeStamp *b)
+{
+ return (a->secs - b->secs) * 1000 + a->msecs - b->msecs;
+}
diff --git a/portable/src/ptypes.c b/portable/src/ptypes.c
new file mode 100644
index 0000000..095a625
--- /dev/null
+++ b/portable/src/ptypes.c
@@ -0,0 +1,38 @@
+/*---------------------------------------------------------------------------*
+ * ptypes.c *
+ * *
+ * Copyright 2007, 2008 Nuance Communciations, Inc. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the 'License'); *
+ * you may not use this file except in compliance with the License. *
+ * *
+ * You may obtain a copy of the License at *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an 'AS IS' BASIS, *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+ * See the License for the specific language governing permissions and *
+ * limitations under the License. *
+ * *
+ *---------------------------------------------------------------------------*/
+
+#include "ptypes.h"
+
+PINLINE ESR_BOOL isNumber(const LCHAR* str)
+{
+ if (!str || !*str)
+ return ESR_FALSE;
+
+ /* ignore minus sign */
+ if (*str == L('-'))
+ ++str;
+
+ while (*str)
+ {
+ if (!isdigit(*str))
+ return ESR_FALSE;
+ ++str;
+ }
+ return ESR_TRUE;
+}