Files
mars-flaim/flaim/util/sharutil.cpp
ahodgkinson f54e6ce080 Changed license to LGPL.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2007-01-23 09:38:48 +00:00

661 lines
15 KiB
C++

//-------------------------------------------------------------------------
// Desc: Utility routines shared among various utilities.
// Tabs: 3
//
// Copyright (c) 1997-2003, 2005-2007 Novell, Inc. All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version 2.1
// of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com.
//
// $Id$
//------------------------------------------------------------------------------
#include "sharutil.h"
FSTATIC RCODE propertyExists(
const char * pszProperty,
const char * pszBuffer,
char ** ppszValue);
/********************************************************************
Desc: Parses command-line parameters
*********************************************************************/
void flmUtilParseParams(
char * pszCommandBuffer,
FLMINT iMaxArgs,
FLMINT * iArgcRV,
const char ** ppArgvRV)
{
FLMINT iArgC = 0;
for (;;)
{
while( (*pszCommandBuffer == ' ') || (*pszCommandBuffer == '\t'))
{
pszCommandBuffer++;
}
if( *pszCommandBuffer == 0)
{
break;
}
if( *pszCommandBuffer == '"' || *pszCommandBuffer == '\'')
{
char ucQuoteChar = *pszCommandBuffer;
pszCommandBuffer++;
ppArgvRV[ iArgC] = pszCommandBuffer;
iArgC++;
while( *pszCommandBuffer && *pszCommandBuffer != ucQuoteChar)
{
pszCommandBuffer++;
}
if( *pszCommandBuffer)
{
*pszCommandBuffer++ = 0;
}
}
else
{
ppArgvRV[ iArgC] = pszCommandBuffer;
iArgC++;
while( *pszCommandBuffer && *pszCommandBuffer != ' ' &&
*pszCommandBuffer != '\t')
{
pszCommandBuffer++;
}
if( *pszCommandBuffer)
{
*pszCommandBuffer++ = 0;
}
}
// Quit if we have reached the maximum allowable number of arguments
if( iArgC == iMaxArgs)
{
break;
}
}
*iArgcRV = iArgC;
}
/****************************************************************************
Desc: a vector set item operation.
****************************************************************************/
#define FLMVECTOR_START_AMOUNT 16
#define FLMVECTOR_GROW_AMOUNT 2
RCODE FlmVector::setElementAt( void * pData, FLMUINT uiIndex)
{
RCODE rc = FERR_OK;
if ( !m_pElementArray)
{
TEST_RC( rc = f_calloc( sizeof( void*) * FLMVECTOR_START_AMOUNT,
&m_pElementArray));
m_uiArraySize = FLMVECTOR_START_AMOUNT;
}
if ( uiIndex >= m_uiArraySize)
{
TEST_RC( rc = f_recalloc(
sizeof( void*) * m_uiArraySize * FLMVECTOR_GROW_AMOUNT,
&m_pElementArray));
m_uiArraySize *= FLMVECTOR_GROW_AMOUNT;
}
m_pElementArray[ uiIndex] = pData;
Exit:
return rc;
}
/****************************************************************************
Desc: a vector get item operation
****************************************************************************/
void * FlmVector::getElementAt( FLMUINT uiIndex)
{
//if you hit this you are indexing into the vector out of bounds.
//unlike a real array, we can catch this here! oh joy!
flmAssert ( uiIndex < m_uiArraySize);
return m_pElementArray[ uiIndex];
}
/****************************************************************************
Desc: append a char (or the same char many times) to the string
****************************************************************************/
RCODE FlmStringAcc::appendCHAR( char ucChar, FLMUINT uiHowMany)
{
RCODE rc = FERR_OK;
if ( uiHowMany == 1)
{
char szStr[ 2];
szStr[ 0] = ucChar;
szStr[ 1] = 0;
rc = this->appendTEXT( szStr);
}
else
{
char * pszStr;
if( RC_BAD( rc = f_alloc( uiHowMany + 1, &pszStr)))
{
goto Exit;
}
f_memset( pszStr, ucChar, uiHowMany);
pszStr[ uiHowMany] = 0;
rc = this->appendTEXT( pszStr);
f_free( &pszStr);
}
Exit:
return rc;
}
/****************************************************************************
Desc: appending text to the accumulator safely. all other methods in
the class funnel through this one, as this one contains the logic
for making sure storage requirements are met.
****************************************************************************/
RCODE FlmStringAcc::appendTEXT(
const char * pszVal)
{
RCODE rc = FERR_OK;
FLMUINT uiIncomingStrLen;
FLMUINT uiStrLen;
//be forgiving if they pass in a NULL
if ( !pszVal)
{
goto Exit;
}
//also be forgiving if they pass a 0-length string
else if ( (uiIncomingStrLen = f_strlen( pszVal)) == 0)
{
goto Exit;
}
//compute total size we need to store the new total
if ( m_bQuickBufActive || m_pszVal)
{
uiStrLen = uiIncomingStrLen + m_uiValStrLen;
}
else
{
uiStrLen = uiIncomingStrLen;
}
//just use small buffer if it's small enough
if ( uiStrLen < FSA_QUICKBUF_BUFFER_SIZE)
{
f_strcat( m_szQuickBuf, pszVal);
m_bQuickBufActive = TRUE;
}
//we are exceeding the quickbuf size, so get the bytes from the heap
else
{
//ensure storage requirements are met (and then some)
if ( m_pszVal == NULL)
{
FLMUINT uiNewBytes = (uiStrLen+1) * 4;
if ( RC_OK ( rc = f_alloc(
(FLMUINT)(sizeof( FLMBYTE) * uiNewBytes),
&m_pszVal)))
{
m_uiBytesAllocatedForPszVal = uiNewBytes;
m_pszVal[ 0] = 0;
}
else
{
goto Exit;
}
}
else if ( (m_uiBytesAllocatedForPszVal-1) < uiStrLen)
{
FLMUINT uiNewBytes = (uiStrLen+1) * 4;
if ( RC_OK( rc = f_realloc(
(FLMUINT)(sizeof( FLMBYTE) * uiNewBytes),
&m_pszVal)))
{
m_uiBytesAllocatedForPszVal = uiNewBytes;
}
else
{
goto Exit;
}
}
//if transitioning from quick buf to heap buf, we need to
//transfer over the quick buf contents and unset the flag
if ( m_bQuickBufActive)
{
m_bQuickBufActive = FALSE;
f_strcpy( m_pszVal, m_szQuickBuf);
//no need to zero out m_szQuickBuf because it will never
//be used again, unless a clear() is issued, in which
//case it will be zeroed out then.
}
//copy over the string
f_strcat( m_pszVal, pszVal);
}
m_uiValStrLen = uiStrLen;
Exit:
return rc;
}
/****************************************************************************
Desc: printf into the FlmStringAcc
****************************************************************************/
RCODE FlmStringAcc::printf(
const char * pszFormatString,
...)
{
f_va_list args;
char * pDestStr = NULL;
RCODE rc = FERR_OK;
if( RC_BAD( rc = f_alloc( 4096, &pDestStr)))
{
goto Exit;
}
f_va_start( args, pszFormatString);
f_vsprintf( pDestStr, pszFormatString, &args);
f_va_end( args);
this->clear();
TEST_RC( rc = this->appendTEXT( pDestStr));
Exit:
if ( pDestStr)
{
f_free( &pDestStr);
}
return rc;
}
/****************************************************************************
Desc: formatted appender like sprintf
****************************************************************************/
RCODE FlmStringAcc::appendf(
const char * pszFormatString,
...)
{
f_va_list args;
char * pDestStr = NULL;
RCODE rc = FERR_OK;
if( RC_BAD( rc = f_alloc( 8192, &pDestStr)))
{
goto Exit;
}
f_va_start( args, pszFormatString);
f_vsprintf( pDestStr, pszFormatString, &args);
f_va_end( args);
TEST_RC( rc = this->appendTEXT( pDestStr));
Exit:
if ( pDestStr)
{
f_free( &pDestStr);
}
return rc;
}
/****************************************************************************
Desc: callback to use to output a line
****************************************************************************/
void utilOutputLine(
const char * pszData,
void * pvUserData)
{
FTX_WINDOW * pMainWindow = (FTX_WINDOW*)pvUserData;
eColorType uiBack;
eColorType uiFore;
FTXWinGetBackFore( pMainWindow, &uiBack, &uiFore);
FTXWinCPrintf( pMainWindow, uiBack, uiFore, "%s\n", pszData);
}
/****************************************************************************
Desc: callback to serve as a 'pager' function when the Usage: help
is too long to fit on one screen.
****************************************************************************/
void utilPressAnyKey(
const char * pszMessage,
void * pvUserData)
{
FTX_WINDOW * pMainWindow = (FTX_WINDOW*)pvUserData;
FLMUINT uiChar;
eColorType uiBack;
eColorType uiFore;
FTXWinGetBackFore( pMainWindow, &uiBack, &uiFore);
FTXWinCPrintf( pMainWindow, uiBack, uiFore, (char*)pszMessage);
while( RC_BAD( FTXWinTestKB( pMainWindow)))
{
f_sleep( 100); //don't hog the cpu
}
FTXWinCPrintf( pMainWindow, uiBack, uiFore,
"\r ");
FTXWinCPrintf( pMainWindow, uiBack, uiFore, "\r");
FTXWinInputChar( pMainWindow, &uiChar);
}
/****************************************************************************
Desc: routine to startup the TUI
****************************************************************************/
RCODE utilInitWindow(
const char * pszTitle,
FLMUINT * puiScreenRows,
FTX_WINDOW ** ppMainWindow,
FLMBOOL * pbShutdown)
{
FTX_SCREEN * pScreen = NULL;
FTX_WINDOW * pTitleWin = NULL;
FLMUINT uiCols;
int iResCode = 0;
if( RC_BAD( FTXInit( pszTitle, 80, 50, FLM_BLUE, FLM_WHITE, NULL, NULL)))
{
iResCode = 1;
goto Exit;
}
FTXSetShutdownFlag( pbShutdown);
if( RC_BAD( FTXScreenInit( pszTitle, &pScreen)))
{
iResCode = 1;
goto Exit;
}
FTXScreenGetSize( pScreen, &uiCols, puiScreenRows);
if( RC_BAD( FTXScreenInitStandardWindows( pScreen, FLM_RED, FLM_WHITE,
FLM_BLUE, FLM_WHITE, FALSE, FALSE, pszTitle,
&pTitleWin, ppMainWindow)))
{
iResCode = 1;
goto Exit;
}
Exit:
return (RCODE)iResCode;
}
/****************************************************************************
Desc: routine to shutdown the TUI
****************************************************************************/
void utilShutdownWindow( void)
{
FTXExit();
}
/****************************************************************************
Desc: fill a buffer with the current (or given) time
****************************************************************************/
FLMUINT utilGetTimeString(
char * pszOutString,
FLMUINT uiBufferSize,
FLMUINT uiInSeconds)
{
F_TMSTAMP timeStamp;
FLMUINT uiSeconds;
if( uiInSeconds != 0)
{
f_timeSecondsToDate( uiInSeconds, &timeStamp);
}
else
{
f_timeGetTimeStamp( &timeStamp);
}
f_timeDateToSeconds( &timeStamp, &uiSeconds);
char pszTemp[ 256];
f_sprintf( pszTemp,
"%4u-%02u-%02u %02u:%02u:%02u",
(unsigned)timeStamp.year,
(unsigned)(timeStamp.month + 1),
(unsigned)timeStamp.day,
(unsigned)timeStamp.hour,
(unsigned)timeStamp.minute,
(unsigned)timeStamp.second);
f_strncpy( pszOutString, pszTemp, uiBufferSize - 1);
pszOutString[ uiBufferSize-1] = 0;
return uiSeconds;
}
#define UTIL_PROP_DELIMITER '!'
FSTATIC RCODE propertyExists(
const char * pszProperty,
const char * pszBuffer,
char ** ppszValue)
{
flmAssert( pszProperty);
FlmStringAcc acc;
RCODE rc = FERR_OK; //returns only memory errors
*ppszValue = NULL;
if ( !pszBuffer)
{
goto Exit;
}
else
{
char * pszValue;
acc.appendf( "%s%c", pszProperty, UTIL_PROP_DELIMITER);
if ( (pszValue = f_strstr( pszBuffer, pszProperty)) != NULL)
{
pszValue = (char *)(1 + f_strchr( pszValue, UTIL_PROP_DELIMITER));
if( RC_BAD( rc = f_strdup( pszValue, ppszValue)))
{
goto Exit;
}
(f_strchr( *ppszValue, '\n'))[ 0] = 0;
}
else
{
goto Exit;
}
}
Exit:
return rc;
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE utilWriteProperty(
const char * pszFile,
const char * pszProp,
const char * pszValue)
{
RCODE rc = FERR_OK;
char * pszContents = NULL;
char * pszExistingProperty;
FlmStringAcc newContents;
IF_FileSystem * pFileSystem = NULL;
//can't have newlines in the props or values
flmAssert( !f_strchr( pszProp, '\n'));
flmAssert( !f_strchr( pszValue, '\n'));
if( RC_BAD( rc = FlmGetFileSystem( &pFileSystem)))
{
goto Exit;
}
if( RC_BAD( pFileSystem->doesFileExist( pszFile)))
{
//add trailing newline
TEST_RC( rc = f_filecpy( pszFile, ""));
}
if ( RC_BAD( f_filetobuf( pszFile, &pszContents)))
{
goto Exit;
}
//propertyExists returns out a new
TEST_RC( rc = propertyExists( pszProp, pszContents, &pszExistingProperty));
if ( !pszExistingProperty)
{
newContents.appendf( "%s%c%s\n", pszProp, UTIL_PROP_DELIMITER, pszValue);
newContents.appendTEXT( pszContents);
}
else
{
f_free( &pszExistingProperty);
FLMUINT uiProps = 0;
//write out nulls in place of the "\n"'s throughout the contents
char * pszNuller = pszContents;
for( ;;)
{
pszNuller = f_strchr( pszNuller, '\n');
if( pszNuller)
{
pszNuller[ 0] = 0;
pszNuller++;
uiProps++;
}
else
{
break;
}
}
char * pszNextLine = pszContents;
char * pszNextProp;
char * pszNextVal;
char * pszBang;
while ( uiProps--)
{
pszBang = f_strchr( pszNextLine, UTIL_PROP_DELIMITER);
flmAssert( pszBang);
pszBang[ 0] = 0;
pszNextProp = pszNextLine;
pszNextVal = pszBang + 1;
if( f_strcmp( pszNextProp, pszProp) != 0)
{
pszBang[ 0] = UTIL_PROP_DELIMITER;
newContents.appendTEXT( pszNextLine);
newContents.appendCHAR( '\n');
}
else
{
newContents.appendf( "%s%c%s\n",
pszNextProp, UTIL_PROP_DELIMITER, pszValue);
pszBang[ 0] = UTIL_PROP_DELIMITER;
}
pszNextLine = pszNextLine + f_strlen( pszNextLine) + 1;
}
}
rc = f_filecpy( pszFile, newContents.getTEXT());
Exit:
if( pszContents)
{
f_free( &pszContents);
}
if( pFileSystem)
{
pFileSystem->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE utilReadProperty(
const char * pszFile,
const char * pszProp,
FlmStringAcc * pAcc)
{
RCODE rc = FERR_OK;
char * pszContents = NULL;
char * pszValue = NULL;
IF_FileSystem * pFileSystem = NULL;
if( RC_BAD( rc = FlmGetFileSystem( &pFileSystem)))
{
goto Exit;
}
if( RC_BAD( pFileSystem->doesFileExist( pszFile)))
{
goto Exit;
}
if ( RC_BAD( f_filetobuf( pszFile, &pszContents)))
{
goto Exit;
}
TEST_RC( rc = propertyExists( pszProp, pszContents, &pszValue));
TEST_RC( rc = pAcc->appendTEXT( pszValue));
Exit:
if( pszValue)
{
f_free( &pszValue);
}
if( pszContents)
{
f_free( &pszContents);
}
if( pFileSystem)
{
pFileSystem->Release();
}
return( rc);
}