/*---------------------------------------------------------------------------* * 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; }