mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-25 05:47:12 +00:00
* emfdb.c: Removed stray semi-colon. Reported on GoAhead mailing lists by Jim Rudnicki <jdrudnicki@yahoo.com>
1051 lines
22 KiB
C
1051 lines
22 KiB
C
/*
|
|
* emfdb.c -- EMF database compatability functions for GoAhead WebServer.
|
|
*
|
|
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
|
*
|
|
* See the file "license.txt" for usage and redistribution license requirements
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
/******************************** Description *********************************/
|
|
/*
|
|
* Textfile-based database support for WebServer 2.1.
|
|
*/
|
|
|
|
/********************************* Includes ***********************************/
|
|
|
|
#include "emfdb.h"
|
|
#include "wsIntrn.h"
|
|
|
|
/********************************* Defines ************************************/
|
|
|
|
#define KEYWORD_TABLE T("TABLE")
|
|
#define KEYWORD_ROW T("ROW")
|
|
|
|
/*********************************** Locals ***********************************/
|
|
|
|
/*
|
|
* Variable to support the basicSet and basicGet functions.
|
|
*/
|
|
|
|
static char_t *basicProdDir = NULL;
|
|
static char_t *basicDefaultDir = T("."); /* Default set to current */
|
|
|
|
/*
|
|
* hAlloc chain list of table schemas to be closed
|
|
*/
|
|
|
|
static int dbMaxTables = 0;
|
|
static dbTable_t **dbListTables = NULL;
|
|
|
|
/****************************** Forward Declarations **************************/
|
|
|
|
static int crack(char_t *buf, char_t **key, char_t **val);
|
|
static char_t *trim(char_t *str);
|
|
static int GetColumnIndex(int tid, char_t *colName);
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Add a schema to the module-internal schema database
|
|
*/
|
|
|
|
int dbRegisterDBSchema(dbTable_t *pTableRegister)
|
|
{
|
|
dbTable_t *pTable;
|
|
int tid;
|
|
|
|
a_assert(pTableRegister);
|
|
|
|
trace(4, T("DB: Registering database table <%s>\n"),
|
|
pTableRegister->name);
|
|
|
|
/*
|
|
* Bump up the size of the table array
|
|
*/
|
|
tid = hAllocEntry((void***) &dbListTables,
|
|
&dbMaxTables, sizeof(dbTable_t));
|
|
|
|
/*
|
|
* Copy the table schema to the last spot in schema array
|
|
*/
|
|
a_assert(dbListTables);
|
|
pTable = dbListTables[tid];
|
|
a_assert(pTable);
|
|
|
|
/*
|
|
* Copy the name of the table
|
|
*/
|
|
pTable->name = bstrdup(B_L, pTableRegister->name);
|
|
|
|
/*
|
|
* Copy the number of columns
|
|
*/
|
|
pTable->nColumns = pTableRegister->nColumns;
|
|
|
|
/*
|
|
* Copy the column definitions
|
|
*/
|
|
if (pTable->nColumns > 0) {
|
|
int i;
|
|
pTable->columnNames = balloc(B_L, sizeof(char_t *) * pTable->nColumns);
|
|
pTable->columnTypes = balloc(B_L, sizeof(int *) * pTable->nColumns);
|
|
|
|
for (i = 0; (i < pTableRegister->nColumns); i++) {
|
|
pTable->columnNames[i] =
|
|
bstrdup(B_L, pTableRegister->columnNames[i]);
|
|
pTable->columnTypes[i] = pTableRegister->columnTypes[i];
|
|
}
|
|
|
|
} else {
|
|
pTable->columnNames = NULL;
|
|
pTable->columnTypes = NULL;
|
|
}
|
|
|
|
/*
|
|
* Zero out the table's data (very important!)
|
|
*/
|
|
pTable->nRows = 0;
|
|
pTable->rows = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* This is provided for compatibility with EMF. Tables are "registered"
|
|
* with staticly defined schemas. There is only one did in this package: 0.
|
|
*/
|
|
|
|
int dbOpen(char_t *tablename, char_t *filename,
|
|
int (*gettime)(int did), int flags)
|
|
{
|
|
basicProdDir = NULL;
|
|
basicDefaultDir = T(".");
|
|
dbMaxTables = 0;
|
|
dbListTables = NULL;
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Delete all the rows of the tables, and all of the tables
|
|
*/
|
|
|
|
void dbClose(int did)
|
|
{
|
|
int table, column;
|
|
dbTable_t *pTable;
|
|
|
|
/*
|
|
* Before doing anything, delete all the contents of the database
|
|
*/
|
|
dbZero(did);
|
|
|
|
/*
|
|
* Now delete the tables
|
|
*/
|
|
for (table = 0; table < dbMaxTables; table++) {
|
|
pTable = dbListTables[table];
|
|
|
|
if (pTable != NULL) {
|
|
/*
|
|
* Delete the table schema
|
|
*/
|
|
if (pTable->nColumns) {
|
|
for (column = 0; column < pTable->nColumns; column++) {
|
|
bfreeSafe(B_L, pTable->columnNames[column]);
|
|
}
|
|
bfreeSafe(B_L, pTable->columnNames);
|
|
bfreeSafe(B_L, pTable->columnTypes);
|
|
}
|
|
/*
|
|
* Delete the table name
|
|
*/
|
|
bfreeSafe(B_L, pTable->name);
|
|
/*
|
|
* Free the table
|
|
*/
|
|
bfreeSafe(B_L, pTable);
|
|
hFree((void ***) &dbListTables, table);
|
|
}
|
|
}
|
|
|
|
if (dbListTables) {
|
|
bfree(B_L, dbListTables);
|
|
}
|
|
|
|
/*
|
|
* Set the global table list to a safe value
|
|
*/
|
|
dbListTables = NULL;
|
|
dbMaxTables = 0;
|
|
}
|
|
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Delete all the data records in all tables
|
|
*/
|
|
|
|
void dbZero(int did)
|
|
{
|
|
int table, row, column, nRows, nColumns;
|
|
int *pRow;
|
|
dbTable_t *pTable;
|
|
|
|
/*
|
|
* Delete all data from all tables
|
|
*/
|
|
for (table = 0; table < dbMaxTables; table++) {
|
|
pTable = dbListTables[table];
|
|
/*
|
|
* Delete the row data contained within the schema
|
|
*/
|
|
if (pTable) {
|
|
nColumns = pTable->nColumns;
|
|
nRows = pTable->nRows;
|
|
for (row = 0; row < nRows; row++) {
|
|
pRow = pTable->rows[row];
|
|
if (pRow) {
|
|
/*
|
|
* Only delete the contents of rows not previously deleted!
|
|
*/
|
|
for (column = 0; column < nColumns; column++) {
|
|
if (pTable->columnTypes[column] == T_STRING) {
|
|
bfreeSafe(B_L, (char_t *)(pRow[column]));
|
|
pRow[column] = (int)NULL;
|
|
}
|
|
}
|
|
|
|
bfreeSafe(B_L, pRow);
|
|
hFree((void ***) &pTable->rows, row);
|
|
}
|
|
}
|
|
|
|
pTable->rows = NULL;
|
|
pTable->nRows = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Find the a row in the table with the given string in the given column
|
|
*/
|
|
|
|
int dbSearchStr(int did, char_t *tablename,
|
|
char_t *colName, char_t *value, int flags)
|
|
{
|
|
int tid, nRows, nColumns, column;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(tablename);
|
|
a_assert(colName);
|
|
a_assert(value);
|
|
|
|
tid = dbGetTableId(0, tablename);
|
|
a_assert(tid >= 0);
|
|
|
|
if ((tid >= 0) && (tid < dbMaxTables) && (dbListTables[tid] != NULL)) {
|
|
pTable = dbListTables[tid];
|
|
} else {
|
|
return DB_ERR_TABLE_NOT_FOUND;
|
|
}
|
|
|
|
nColumns = pTable->nColumns;
|
|
nRows = pTable->nRows;
|
|
column = GetColumnIndex(tid, colName);
|
|
a_assert (column >= 0);
|
|
|
|
if (column >= 0) {
|
|
char_t *compareVal;
|
|
int row, *pRow;
|
|
/*
|
|
* Scan through rows until we find a match.
|
|
* Note that some of these rows may be deleted!
|
|
*/
|
|
row = 0;
|
|
while (row < nRows) {
|
|
pRow = pTable->rows[row];
|
|
if (pRow) {
|
|
compareVal = (char_t *)(pRow[column]);
|
|
if (compareVal && (gstrcmp(compareVal, value) == 0)) {
|
|
return row;
|
|
}
|
|
}
|
|
row++;
|
|
}
|
|
} else {
|
|
/*
|
|
* Return -2 if search column was not found
|
|
*/
|
|
trace(3, T("DB: Unable to find column <%s> in table <%s>\n"),
|
|
colName, tablename);
|
|
return DB_ERR_COL_NOT_FOUND;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Add a new row to the given table. Return the new row ID.
|
|
*/
|
|
|
|
int dbAddRow(int did, char_t *tablename)
|
|
{
|
|
int tid, size;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(tablename);
|
|
|
|
tid = dbGetTableId(0, tablename);
|
|
a_assert(tid >= 0);
|
|
|
|
if ((tid >= 0) && (tid < dbMaxTables) && (dbListTables[tid] != NULL)) {
|
|
pTable = dbListTables[tid];
|
|
} else {
|
|
return DB_ERR_TABLE_NOT_FOUND;
|
|
}
|
|
|
|
a_assert(pTable);
|
|
|
|
if (pTable) {
|
|
trace(5, T("DB: Adding a row to table <%s>\n"), tablename);
|
|
|
|
size = pTable->nColumns * max(sizeof(int), sizeof(char_t *));
|
|
return hAllocEntry((void***) &(pTable->rows), &(pTable->nRows), size);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Delete a row in the table.
|
|
*/
|
|
|
|
int dbDeleteRow(int did, char_t *tablename, int row)
|
|
{
|
|
int tid, nColumns, nRows;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(tablename);
|
|
tid = dbGetTableId(0, tablename);
|
|
a_assert(tid >= 0);
|
|
|
|
if ((tid >= 0) && (tid < dbMaxTables) && (dbListTables[tid] != NULL)) {
|
|
pTable = dbListTables[tid];
|
|
} else {
|
|
return DB_ERR_TABLE_NOT_FOUND;
|
|
}
|
|
|
|
nColumns = pTable->nColumns;
|
|
nRows = pTable->nRows;
|
|
|
|
if ((row >= 0) && (row < nRows)) {
|
|
int *pRow = pTable->rows[row];
|
|
|
|
if (pRow) {
|
|
int column = 0;
|
|
/*
|
|
* Free up any allocated strings
|
|
*/
|
|
while (column < nColumns) {
|
|
if (pRow[column] &&
|
|
(pTable->columnTypes[column] == T_STRING)) {
|
|
bfree(B_L, (char_t *)pRow[column]);
|
|
}
|
|
|
|
column++;
|
|
}
|
|
/*
|
|
* Zero out the row for safety
|
|
*/
|
|
memset(pRow, 0, nColumns * max(sizeof(int), sizeof(char_t *)));
|
|
|
|
bfreeSafe(B_L, pRow);
|
|
pTable->nRows = hFree((void ***)&pTable->rows, row);
|
|
trace(5, T("DB: Deleted row <%d> from table <%s>\n"),
|
|
row, tablename);
|
|
}
|
|
return 0;
|
|
} else {
|
|
trace(3, T("DB: Unable to delete row <%d> from table <%s>\n"),
|
|
row, tablename);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*
|
|
* Grow the rows in the table to the nominated size.
|
|
*/
|
|
|
|
int dbSetTableNrow(int did, char_t *tablename, int nNewRows)
|
|
{
|
|
int nRet, tid, nRows, nColumns;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(tablename);
|
|
tid = dbGetTableId(0, tablename);
|
|
a_assert(tid >= 0) ;
|
|
|
|
if ((tid >= 0) && (tid < dbMaxTables) && (dbListTables[tid] != NULL)) {
|
|
pTable = dbListTables[tid];
|
|
} else {
|
|
return DB_ERR_TABLE_NOT_FOUND;
|
|
}
|
|
|
|
nRet = -1;
|
|
|
|
a_assert(pTable);
|
|
if (pTable) {
|
|
nColumns = pTable->nColumns;
|
|
nRows = pTable->nRows;
|
|
nRet = 0;
|
|
|
|
if (nRows >= nNewRows) {
|
|
/*
|
|
* If number of rows already allocated exceeds requested number, do nothing
|
|
*/
|
|
trace(4, T("DB: Ignoring row set to <%d> in table <%s>\n"),
|
|
nNewRows, tablename);
|
|
} else {
|
|
trace(4, T("DB: Setting rows to <%d> in table <%s>\n"),
|
|
nNewRows, tablename);
|
|
while (pTable->nRows < nNewRows) {
|
|
if (dbAddRow(did, tablename) < 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Return the number of rows in the given table
|
|
*/
|
|
|
|
int dbGetTableNrow(int did, char_t *tablename)
|
|
{
|
|
int tid;
|
|
|
|
a_assert(tablename);
|
|
tid = dbGetTableId(did, tablename);
|
|
|
|
if ((tid >= 0) && (tid < dbMaxTables) && (dbListTables[tid] != NULL)) {
|
|
return (dbListTables[tid])->nRows;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Do table driven read of the database
|
|
*/
|
|
|
|
int dbReadInt(int did, char_t *table, char_t *column, int row, int *returnValue)
|
|
{
|
|
int colIndex, *pRow, tid;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(table);
|
|
a_assert(column);
|
|
a_assert(returnValue);
|
|
|
|
tid = dbGetTableId(0, table);
|
|
a_assert(tid >= 0);
|
|
|
|
/*
|
|
* Return -6 if table is not found
|
|
*/
|
|
if (tid < 0) {
|
|
return DB_ERR_TABLE_NOT_FOUND;
|
|
}
|
|
|
|
/*
|
|
* Return -7 if table id has been deleted
|
|
*/
|
|
pTable = dbListTables[tid];
|
|
if (pTable == NULL) {
|
|
return DB_ERR_TABLE_DELETED;
|
|
}
|
|
|
|
a_assert(row >= 0);
|
|
|
|
if ((row >= 0) && (row < pTable->nRows)) {
|
|
colIndex = GetColumnIndex(tid, column);
|
|
a_assert(colIndex >= 0);
|
|
|
|
if (colIndex >= 0) {
|
|
pRow = pTable->rows[row];
|
|
if (pRow) {
|
|
*returnValue = pRow[colIndex];
|
|
return 0;
|
|
}
|
|
return DB_ERR_ROW_DELETED;
|
|
}
|
|
return DB_ERR_COL_NOT_FOUND;
|
|
}
|
|
|
|
return DB_ERR_ROW_NOT_FOUND;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* dbReadStr calls dbReadInt to do table driven read of database
|
|
*/
|
|
|
|
int dbReadStr(int did, char_t *table, char_t *column, int row,
|
|
char_t **returnValue)
|
|
{
|
|
return dbReadInt(did, table, column, row, (int *)returnValue);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* The dbWriteInt function writes a value into a table at a given row and
|
|
* column. The existence of the row and column is verified before the
|
|
* write. 0 is returned on succes, -1 is returned on error.
|
|
*/
|
|
|
|
int dbWriteInt(int did, char_t *table, char_t *column, int row, int iData)
|
|
{
|
|
int tid, colIndex, *pRow;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(table);
|
|
a_assert(column);
|
|
|
|
/*
|
|
* Make sure that this table exists
|
|
*/
|
|
tid = dbGetTableId(0, table);
|
|
a_assert(tid >= 0);
|
|
|
|
if (tid < 0) {
|
|
return DB_ERR_TABLE_NOT_FOUND;
|
|
}
|
|
|
|
pTable = dbListTables[tid];
|
|
|
|
if (pTable) {
|
|
/*
|
|
* Make sure that the column exists
|
|
*/
|
|
colIndex = GetColumnIndex(tid, column);
|
|
a_assert(colIndex >= 0);
|
|
if (colIndex >= 0) {
|
|
/*
|
|
* Make sure that the row exists
|
|
*/
|
|
a_assert((row >= 0) && (row < pTable->nRows));
|
|
if ((row >= 0) && (row < pTable->nRows)) {
|
|
pRow = pTable->rows[row];
|
|
if (pRow) {
|
|
pRow[colIndex] = iData;
|
|
return 0;
|
|
}
|
|
return DB_ERR_ROW_DELETED;
|
|
}
|
|
return DB_ERR_ROW_NOT_FOUND;
|
|
}
|
|
return DB_ERR_COL_NOT_FOUND;
|
|
}
|
|
|
|
return DB_ERR_TABLE_DELETED;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* The dbWriteStr function writes a string value into a table at a given row
|
|
* and column. The existence of the row and column is verified before the
|
|
* write. The column is also checked to confirm it is a string field.
|
|
* 0 is returned on succes, -1 is returned on error.
|
|
*/
|
|
|
|
int dbWriteStr(int did, char_t *table, char_t *column, int row, char_t *s)
|
|
{
|
|
int tid, colIndex;
|
|
int *pRow;
|
|
char_t *ptr;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(table);
|
|
a_assert(column);
|
|
|
|
tid = dbGetTableId(0, table);
|
|
a_assert(tid >= 0);
|
|
|
|
if (tid < 0) {
|
|
return DB_ERR_TABLE_NOT_FOUND;
|
|
}
|
|
|
|
/*
|
|
* Make sure that this table exists
|
|
*/
|
|
pTable = dbListTables[tid];
|
|
a_assert(pTable);
|
|
if (!pTable) {
|
|
return DB_ERR_TABLE_DELETED;
|
|
}
|
|
|
|
/*
|
|
* Make sure that this column exists
|
|
*/
|
|
colIndex = GetColumnIndex(tid, column);
|
|
if (colIndex < 0) {
|
|
return DB_ERR_COL_NOT_FOUND;
|
|
}
|
|
|
|
/*
|
|
* Make sure that this column is a string column
|
|
*/
|
|
if (pTable->columnTypes[colIndex] != T_STRING) {
|
|
return DB_ERR_BAD_FORMAT;
|
|
}
|
|
|
|
/*
|
|
* Make sure that the row exists
|
|
*/
|
|
a_assert((row >= 0) && (row < pTable->nRows));
|
|
if ((row >= 0) && (row < pTable->nRows)) {
|
|
pRow = pTable->rows[row];
|
|
} else {
|
|
return DB_ERR_ROW_NOT_FOUND;
|
|
}
|
|
|
|
if (!pRow) {
|
|
return DB_ERR_ROW_DELETED;
|
|
}
|
|
|
|
/*
|
|
* If the column already has a value, be sure to delete it to prevent
|
|
* memory leaks.
|
|
*/
|
|
if (pRow[colIndex]) {
|
|
bfree(B_L, (char_t *) pRow[colIndex]);
|
|
}
|
|
|
|
/*
|
|
* Make sure we make a copy of the string to write into the column.
|
|
* This allocated string will be deleted when the row is deleted.
|
|
*/
|
|
ptr = bstrdup(B_L, s);
|
|
pRow[colIndex] = (int)ptr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Print a key-value pair to a file
|
|
*/
|
|
|
|
static int dbWriteKeyValue(int fd, char_t *key, char_t *value)
|
|
{
|
|
int rc;
|
|
int len;
|
|
char_t *pLineOut;
|
|
|
|
a_assert(key && *key);
|
|
a_assert(value);
|
|
|
|
fmtAlloc(&pLineOut, BUF_MAX, T("%s=%s\n"), key, value);
|
|
|
|
if (pLineOut) {
|
|
len = gstrlen(pLineOut);
|
|
#if CE
|
|
rc = writeUniToAsc(fd, pLineOut, len);
|
|
#else
|
|
rc = gwrite(fd, pLineOut, len);
|
|
#endif
|
|
bfree(B_L, pLineOut);
|
|
} else {
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Persist a database to a file
|
|
*/
|
|
|
|
int dbSave(int did, char_t *filename, int flags)
|
|
{
|
|
int row, column, nColumns, nRows, fd, rc;
|
|
int *colTypes, *pRow, nRet, tid;
|
|
char_t *path, *tmpFile, *tmpNum;
|
|
char_t **colNames;
|
|
dbTable_t *pTable;
|
|
|
|
trace(5, T("DB: About to save database to file\n"));
|
|
|
|
a_assert(dbMaxTables > 0);
|
|
|
|
/*
|
|
* First write to a temporary file, then switch around later.
|
|
*/
|
|
fmtAlloc(&tmpFile, FNAMESIZE, T("%s/data.tmp"), basicGetProductDir());
|
|
if ((fd = gopen(tmpFile,
|
|
O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0666)) < 0) {
|
|
trace(1, T("WARNING: Failed to open file %s\n"), tmpFile);
|
|
bfree(B_L, tmpFile);
|
|
return -1;
|
|
}
|
|
|
|
nRet = 0;
|
|
|
|
for (tid = 0; (tid < dbMaxTables) && (nRet != -1); tid++) {
|
|
pTable = dbListTables[tid];
|
|
|
|
if (pTable) {
|
|
/*
|
|
* Print the TABLE=tableName directive to the file
|
|
*/
|
|
rc = dbWriteKeyValue(fd, KEYWORD_TABLE, pTable->name);
|
|
|
|
nColumns = pTable->nColumns;
|
|
nRows = pTable->nRows;
|
|
|
|
for (row = 0; (row < nRows) && (nRet == 0); row++) {
|
|
pRow = pTable->rows[row];
|
|
/*
|
|
* if row is NULL, the row has been deleted, so don't
|
|
* write it out.
|
|
*/
|
|
if ((pRow == NULL) || (pRow[0] == '\0') ||
|
|
(*(char_t *)(pRow[0]) == '\0')) {
|
|
continue;
|
|
}
|
|
/*
|
|
* Print the ROW=rowNumber directive to the file
|
|
*/
|
|
fmtAlloc(&tmpNum, 20, T("%d"), row);
|
|
rc = dbWriteKeyValue(fd, KEYWORD_ROW, tmpNum);
|
|
bfreeSafe(B_L, tmpNum);
|
|
|
|
colNames = pTable->columnNames;
|
|
colTypes = pTable->columnTypes;
|
|
/*
|
|
* Print the key-value pairs (COLUMN=value) for data cells
|
|
*/
|
|
for (column = 0; (column < nColumns) && (rc >= 0);
|
|
column++, colNames++, colTypes++) {
|
|
if (*colTypes == T_STRING) {
|
|
rc = dbWriteKeyValue(fd, *colNames,
|
|
(char_t *)(pRow[column]));
|
|
} else {
|
|
fmtAlloc(&tmpNum, 20, T("%d"), pRow[column]);
|
|
rc = dbWriteKeyValue(fd, *colNames, tmpNum);
|
|
bfreeSafe(B_L, tmpNum);
|
|
}
|
|
}
|
|
|
|
if (rc < 0) {
|
|
trace(1, T("WARNING: Failed to write to file %s\n"),
|
|
tmpFile);
|
|
nRet = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gclose(fd);
|
|
|
|
/*
|
|
* Replace the existing file with the temporary file, if no errors
|
|
*/
|
|
if (nRet == 0) {
|
|
fmtAlloc(&path, FNAMESIZE, T("%s/%s"), basicGetProductDir(), filename);
|
|
|
|
gunlink(path);
|
|
if (grename(tmpFile, path) != 0) {
|
|
trace(1, T("WARNING: Failed to rename %s to %s\n"), tmpFile, path);
|
|
nRet = -1;
|
|
}
|
|
|
|
bfree(B_L, path);
|
|
}
|
|
|
|
bfree(B_L, tmpFile);
|
|
|
|
return nRet;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Crack a keyword=value string into keyword and value. We can change buf.
|
|
*/
|
|
|
|
static int crack(char_t *buf, char_t **key, char_t **val)
|
|
{
|
|
char_t *ptr;
|
|
|
|
if ((ptr = gstrrchr(buf, '\n')) != NULL ||
|
|
(ptr = gstrrchr(buf, '\r')) != NULL) {
|
|
*ptr = '\0';
|
|
}
|
|
|
|
/*
|
|
* Find the = sign. It must exist.
|
|
*/
|
|
if ((ptr = gstrstr(buf, T("="))) == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
*ptr++ = '\0';
|
|
*key = trim(buf);
|
|
*val = trim(ptr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Parse the file. These files consist of key-value pairs, separated by the
|
|
* "=" sign. Parsing of tables starts with the "TABLE=value" pair, and rows
|
|
* are parsed starting with the "ROW=value" pair.
|
|
*/
|
|
|
|
int dbLoad(int did, char_t *filename, int flags)
|
|
{
|
|
gstat_t sbuf;
|
|
char_t *buf, *keyword, *value, *path, *ptr;
|
|
char_t *tablename;
|
|
int fd, tid, row;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(did >= 0);
|
|
|
|
fmtAlloc(&path, FNAMESIZE, T("%s/%s"), basicGetProductDir(), filename);
|
|
trace(4, T("DB: About to read data file <%s>\n"), path);
|
|
|
|
if (gstat(path, &sbuf) < 0) {
|
|
trace(3, T("DB: Failed to stat persistent data file.\n"));
|
|
bfree(B_L, path);
|
|
return -1;
|
|
}
|
|
|
|
fd = gopen(path, O_RDONLY | O_BINARY, 0666);
|
|
bfree(B_L, path);
|
|
|
|
if (fd < 0) {
|
|
trace(3, T("DB: No persistent data file present.\n"));
|
|
return -1;
|
|
}
|
|
|
|
if (sbuf.st_size <= 0) {
|
|
trace(3, T("DB: Persistent data file is empty.\n"));
|
|
gclose(fd);
|
|
return -1;
|
|
}
|
|
/*
|
|
* Read entire file into temporary buffer
|
|
*/
|
|
buf = balloc(B_L, sbuf.st_size + 1);
|
|
#if CE
|
|
if (readAscToUni(fd, &buf, sbuf.st_size) != (int)sbuf.st_size) {
|
|
#else
|
|
if (gread(fd, buf, sbuf.st_size) != (int)sbuf.st_size) {
|
|
#endif
|
|
trace(3, T("DB: Persistent data read failed.\n"));
|
|
bfree(B_L, buf);
|
|
gclose(fd);
|
|
return -1;
|
|
}
|
|
|
|
gclose(fd);
|
|
*(buf + sbuf.st_size) = '\0';
|
|
|
|
row = -1;
|
|
tid = -1;
|
|
pTable = NULL;
|
|
ptr = gstrtok(buf, T("\n"));
|
|
tablename = NULL;
|
|
|
|
do {
|
|
if (crack(ptr, &keyword, &value) < 0) {
|
|
trace(5, T("DB: Failed to crack line %s\n"), ptr);
|
|
continue;
|
|
}
|
|
|
|
a_assert(keyword && *keyword);
|
|
|
|
if (gstrcmp(keyword, KEYWORD_TABLE) == 0) {
|
|
/*
|
|
* Table name found, check to see if it's registered
|
|
*/
|
|
if (tablename) {
|
|
bfree(B_L, tablename);
|
|
}
|
|
|
|
tablename = bstrdup(B_L, value);
|
|
tid = dbGetTableId(did, tablename);
|
|
|
|
if (tid >= 0) {
|
|
pTable = dbListTables[tid];
|
|
} else {
|
|
pTable = NULL;
|
|
}
|
|
|
|
} else if (gstrcmp(keyword, KEYWORD_ROW) == 0) {
|
|
/*
|
|
* Row/Record indicator found, add a new row to table
|
|
*/
|
|
if (tid >= 0) {
|
|
int nRows = dbGetTableNrow(did, tablename);
|
|
|
|
if (dbSetTableNrow(did, tablename, nRows + 1) == 0) {
|
|
row = nRows;
|
|
}
|
|
}
|
|
|
|
} else if (row != -1) {
|
|
/*
|
|
* some other data found, assume it's a COLUMN=value
|
|
*/
|
|
int nColumn = GetColumnIndex(tid, keyword);
|
|
|
|
if ((nColumn >= 0) && (pTable != NULL)) {
|
|
int nColumnType = pTable->columnTypes[nColumn];
|
|
if (nColumnType == T_STRING) {
|
|
dbWriteStr(did, tablename, keyword, row, value);
|
|
} else {
|
|
dbWriteInt(did, tablename, keyword, row, gstrtoi(value));
|
|
}
|
|
}
|
|
}
|
|
} while ((ptr = gstrtok(NULL, T("\n"))) != NULL);
|
|
|
|
if (tablename) {
|
|
bfree(B_L, tablename);
|
|
}
|
|
|
|
bfree(B_L, buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Return a table id given the table name
|
|
*/
|
|
|
|
int dbGetTableId(int did, char_t *tablename)
|
|
{
|
|
int tid;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(tablename);
|
|
|
|
for (tid = 0; (tid < dbMaxTables); tid++) {
|
|
if ((pTable = dbListTables[tid]) != NULL) {
|
|
if (gstrcmp(tablename, pTable->name) == 0) {
|
|
return tid;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Return a pointer to the table name, given its ID
|
|
*/
|
|
|
|
char_t *dbGetTableName(int did, int tid)
|
|
{
|
|
if ((tid >= 0) && (tid < dbMaxTables) && (dbListTables[tid] != NULL)) {
|
|
return (dbListTables[tid])->name;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Trim leading white space.
|
|
*/
|
|
|
|
static char_t *trim(char_t *str)
|
|
{
|
|
while (isspace((int)*str)) {
|
|
str++;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Return a column index given the column name
|
|
*/
|
|
|
|
static int GetColumnIndex(int tid, char_t *colName)
|
|
{
|
|
int column;
|
|
dbTable_t *pTable;
|
|
|
|
a_assert(colName);
|
|
|
|
if ((tid >= 0) && (tid < dbMaxTables) && (dbListTables[tid] != NULL)) {
|
|
pTable = dbListTables[tid];
|
|
|
|
for (column = 0; (column < pTable->nColumns); column++) {
|
|
if (gstrcmp(colName, pTable->columnNames[column]) == 0)
|
|
return column;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Set the prefix-directory
|
|
*/
|
|
|
|
void basicSetProductDir(char_t *proddir)
|
|
{
|
|
int len;
|
|
|
|
if (basicProdDir != NULL) {
|
|
bfree(B_L, basicProdDir);
|
|
}
|
|
|
|
basicProdDir = bstrdup(B_L, proddir);
|
|
/*
|
|
* Make sure that prefix-directory doesn't end with a '/'
|
|
*/
|
|
len = gstrlen(basicProdDir);
|
|
if ((len > 0) && *(basicProdDir + len - 1) == '/') {
|
|
*(basicProdDir+len-1) = '\0';
|
|
}
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Return the prefix-directory
|
|
*/
|
|
|
|
char_t *basicGetProductDir()
|
|
{
|
|
if (basicProdDir) {
|
|
return basicProdDir;
|
|
} else {
|
|
return basicDefaultDir;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************/
|