Initial community commit

This commit is contained in:
Jef 2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit fc06254474
16440 changed files with 4239995 additions and 2 deletions

View file

@ -0,0 +1,78 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
Binary32Field Class
--------------------------------------------------------------------------- */
#include "nde.h"
#include "Binary32Field.h"
#include "ndestring.h"
//---------------------------------------------------------------------------
Binary32Field::Binary32Field(const uint8_t *_Data, size_t len) : BinaryField(_Data, len)
{
InitField();
}
//---------------------------------------------------------------------------
void Binary32Field::InitField(void)
{
Type = FIELD_BINARY32;
}
//---------------------------------------------------------------------------
Binary32Field::Binary32Field()
{
InitField();
}
//---------------------------------------------------------------------------
void Binary32Field::ReadTypedData(const uint8_t *data, size_t len)
{
uint32_t c;
size_t pos = 0;
CHECK_INT(len); //len-=4;
c = GET_INT(); pos += 4;
if (c && c<=len)
{
size_t size = c;
uint8_t *buf = (uint8_t *)malloc(size);
GET_BINARY(buf, data, c, pos);
Data = CFDataCreateWithBytesNoCopy(NULL, buf, size, kCFAllocatorMalloc);
}
}
//---------------------------------------------------------------------------
void Binary32Field::WriteTypedData(uint8_t *data, size_t len)
{
uint32_t c;
size_t pos = 0;
CHECK_INT(len); //len-=4;
size_t Size = CFDataGetLength(Data);
if (Data && Size<=len)
{
c = CFDataGetLength(Data);
PUT_INT(c); pos += 4;
CFDataGetBytes(Data, CFRangeMake(0, Size), data+pos);
}
else
{
PUT_INT(0);
}
}
//---------------------------------------------------------------------------
size_t Binary32Field::GetDataSize(void)
{
if (!Data)
return 4;
return CFDataGetLength(Data) + 4;
}

View file

@ -0,0 +1,32 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
Binary32Field Class Prototypes
--------------------------------------------------------------------------- */
#ifndef __NDE_BINARY32FIELD_H
#define __NDE_BINARY32FIELD_H
#include "BinaryField.h"
#include <bfc/platform/types.h>
class Binary32Field : public BinaryField
{
protected:
virtual void ReadTypedData(const uint8_t *, size_t len);
virtual void WriteTypedData(uint8_t *, size_t len);
virtual size_t GetDataSize(void);
void InitField(void);
public:
Binary32Field(const uint8_t *Data, size_t len);
Binary32Field();
};
#endif

172
Src/nde/osx/BinaryField.cpp Normal file
View file

@ -0,0 +1,172 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
BinaryField Class
--------------------------------------------------------------------------- */
#include "../nde.h"
#include "BinaryField.h"
//---------------------------------------------------------------------------
BinaryField::BinaryField(const uint8_t *_Data, int len)
{
InitField();
Type = FIELD_BINARY;
if (_Data && len > 0)
{
Data = CFDataCreate(NULL, _Data, len);
}
}
//---------------------------------------------------------------------------
void BinaryField::InitField(void)
{
Type = FIELD_BINARY;
Data = NULL;
}
//---------------------------------------------------------------------------
BinaryField::BinaryField()
{
InitField();
}
//---------------------------------------------------------------------------
BinaryField::~BinaryField()
{
CFRelease(Data);
}
//---------------------------------------------------------------------------
void BinaryField::ReadTypedData(const uint8_t *data, size_t len)
{
unsigned short c;
int pos = 0;
CHECK_SHORT(len);
c = GET_SHORT(); pos += 2;
if (c && c<=len)
{
Data = CFDataCreate(NULL, data+pos, c);
}
}
//---------------------------------------------------------------------------
void BinaryField::WriteTypedData(uint8_t *data, size_t len)
{
unsigned short c;
size_t pos = 0;
CHECK_SHORT(len);
size_t Size = CFDataGetLength(Data);
if (Data && Size<=len)
{
c = CFDataGetLength(Data);
PUT_SHORT(c); pos += 2;
CFDataGetBytes(Data, CFRangeMake(0, Size), data+pos);
}
else
{
PUT_SHORT(0);
}
}
//---------------------------------------------------------------------------
const uint8_t *BinaryField::GetData(size_t *len)
{
if (len)
*len = CFDataGetLength(Data);
return CFDataGetBytePtr(Data);
}
//---------------------------------------------------------------------------
void BinaryField::SetData(const uint8_t *_Data, size_t len)
{
if (!_Data || !len) return;
if (Data)
CFRelease(Data);
Data = CFDataCreate(NULL, _Data, len);
}
CFDataRef BinaryField::GetCFData()
{
return Data;
}
//---------------------------------------------------------------------------
size_t BinaryField::GetDataSize(void)
{
if (!Data) return 2;
return CFDataGetLength(Data) + 2;
}
//---------------------------------------------------------------------------
int BinaryField::Compare(Field *Entry)
{
if (!Entry) return -1;
size_t compare_length;
const uint8_t *compare_data = ((BinaryField*)Entry)->GetData(&compare_length);
size_t size;
const uint8_t *data = GetData(&size);
return memcmp(data, compare_data, min(compare_length, size));
}
//---------------------------------------------------------------------------
bool BinaryField::ApplyFilter(Field *FilterData, int op)
{
size_t l, s;
const uint8_t *p = ((BinaryField *)FilterData)->GetData(&l);
const uint8_t *d = GetData(&s);
if (!p)
p = (const uint8_t *)"";
if (!d)
d = (const uint8_t *)"";
bool r;
switch (op)
{
case FILTER_EQUALS:
if (l != s)
r = false;
else
r = !memcmp(d, p, min(s, l));
break;
case FILTER_CONTAINS:
if (l > s)
r = FALSE;
else
r = !!memmem(d, p, s, l);
break;
case FILTER_ABOVE:
r = (memcmp(d, p, min(s, l)) > 0);
break;
case FILTER_BELOW:
r = (memcmp(d, p, min(s, l)) < 0);
break;
case FILTER_BELOWOREQUAL:
r = (memcmp(d, p, min(s, l)) <= 0);
break;
case FILTER_ABOVEOREQUAL:
r = (memcmp(d, p, min(s, l)) >= 0);
break;
case FILTER_ISEMPTY:
r = (s == 0);
break;
case FILTER_ISNOTEMPTY:
r = (s != 0);
break;
default:
r = true;
break;
}
return r;
}

38
Src/nde/osx/BinaryField.h Normal file
View file

@ -0,0 +1,38 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
BinaryField Class Prototypes
--------------------------------------------------------------------------- */
#ifndef __BINARYFIELD_H
#define __BINARYFIELD_H
#include "Field.h"
#include <bfc/platform/types.h>
class BinaryField : public Field
{
protected:
virtual void ReadTypedData(const uint8_t *, size_t len);
virtual void WriteTypedData(uint8_t *, size_t len);
virtual size_t GetDataSize(void);
virtual int Compare(Field *Entry);
virtual bool ApplyFilter(Field *Data, int flags);
void InitField(void);
CFDataRef Data;
public:
~BinaryField();
BinaryField(const uint8_t *Data, int len);
BinaryField();
const uint8_t *GetData(size_t *len);
void SetData(const uint8_t *Data, size_t len);
CFDataRef GetCFData();
};
#endif

160
Src/nde/osx/ColumnField.cpp Normal file
View file

@ -0,0 +1,160 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
ColumnField Class
Mac OS X implementation
Field data layout:
[1 byte] Field Type
[1 byte] Unused (maybe convert to 'searchable')
[1 byte] Name Length
[Name Length bytes] Name (UTF-8)
--------------------------------------------------------------------------- */
#include "../nde.h"
//---------------------------------------------------------------------------
ColumnField::ColumnField(unsigned char FieldID, CFStringRef FieldName, unsigned char FieldType, Table *parentTable)
{
InitField();
Type = FIELD_COLUMN;
MyType = FieldType;
Name = (CFStringRef)CFRetain(FieldName);
ID = FieldID;
}
//---------------------------------------------------------------------------
void ColumnField::InitField(void)
{
searchable = false;
MyType = FIELD_UNKNOWN;
Type = FIELD_COLUMN;
Name = NULL;
ID = 0;
}
//---------------------------------------------------------------------------
ColumnField::ColumnField()
{
InitField();
}
//---------------------------------------------------------------------------
ColumnField::~ColumnField()
{
if (Name)
CFRelease(Name);
}
void ColumnField::SetSearchable(bool val)
{
searchable=val;
}
bool ColumnField::IsSearchableField() const
{
return searchable;
}
//---------------------------------------------------------------------------
void ColumnField::ReadTypedData(const uint8_t *data, size_t len)
{
unsigned char c;
int pos=0;
CHECK_CHAR(len);
MyType = GET_CHAR(); pos++;
CHECK_CHAR(len);
pos++;
CHECK_CHAR(len);
c = GET_CHAR(); pos++;
if (c)
{
CHECK_BIN(len, c);
if (Name)
CFRelease(Name);
Name = CFStringCreateWithBytes(kCFAllocatorDefault, data+pos, c, kCFStringEncodingUTF8, false);
}
}
//---------------------------------------------------------------------------
void ColumnField::WriteTypedData(uint8_t *data, size_t len)
{
int pos = 0;
CHECK_CHAR(len);
PUT_CHAR(MyType); pos++;
CHECK_CHAR(len);
PUT_CHAR(0/*(char)indexUnique*/);
pos++;
if (Name)
{
CFIndex lengthRequired=0;
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, NULL, 0, &lengthRequired);
CHECK_BIN(len, lengthRequired+1);
PUT_CHAR(lengthRequired); pos++;
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, data+pos, lengthRequired, 0);
}
else
{
PUT_CHAR(0);
}
}
//---------------------------------------------------------------------------
unsigned char ColumnField::GetDataType(void)
{
return MyType;
}
//---------------------------------------------------------------------------
void ColumnField::SetDataType(unsigned char type)
{
if ((MyType == FIELD_INTEGER || MyType == FIELD_BOOLEAN || MyType == FIELD_DATETIME || MyType == FIELD_LENGTH) &&
(type == FIELD_INTEGER || type == FIELD_BOOLEAN || type == FIELD_DATETIME || type == FIELD_LENGTH)) {
MyType = type;
}
// going from string to filename or filename to string is OK
if ((MyType == FIELD_FILENAME && type == FIELD_STRING)
|| (MyType == FIELD_STRING && type == FIELD_FILENAME))
{
MyType = type;
}
}
//---------------------------------------------------------------------------
CFStringRef ColumnField::GetFieldName(void)
{
return Name;
}
//---------------------------------------------------------------------------
size_t ColumnField::GetDataSize(void)
{
if (Name)
{
CFIndex lengthRequired=0;
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, NULL, 0, &lengthRequired);
return lengthRequired+3;
}
else
return 3;
}
//---------------------------------------------------------------------------
int ColumnField::Compare(Field * /*Entry*/)
{
return 0;
}

49
Src/nde/osx/ColumnField.h Normal file
View file

@ -0,0 +1,49 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
ColumnField Class Prototypes
Mac OS X implementation
--------------------------------------------------------------------------- */
#ifndef __COLUMNFIELD_H
#define __COLUMNFIELD_H
#include "Field.h"
#include "LinkedList.h"
#include "Table.h"
#include "Scanner.h"
class ColumnField : public Field
{
public:
ColumnField(unsigned char FieldID, CFStringRef FieldName, unsigned char FieldType, Table *parentTable);
ColumnField();
~ColumnField();
/* Field implementation */
virtual void ReadTypedData(const uint8_t *, size_t len);
virtual void WriteTypedData(uint8_t *, size_t len);
virtual size_t GetDataSize(void);
virtual int Compare(Field *Entry);
/* ColumnField methods */
void InitField(void);
void SetDataType(unsigned char type);
bool IsSearchableField() const;
void SetSearchable(bool val);
unsigned char GetDataType(void);
CFStringRef GetFieldName(void);
protected:
bool searchable;
CFStringRef Name;
unsigned char MyType;
};
#endif

View file

@ -0,0 +1,45 @@
#include "FilenameField.h"
#include "nde.h"
/*
Mac OS X implementation of FilenameField
only the equals operator will be case-sensitive. substring search, ends, starts, etc. will be case-insensitive,
to make things like "filename ends .mp3" easier
TODO: it'd be massive overhead, but it'd be more correct to check if the file system is actually case sensitive (for the path being searched)
*/
//---------------------------------------------------------------------------
FilenameField::FilenameField(CFStringRef Str) : StringField(Str)
{
Type = FIELD_FILENAME;
}
//---------------------------------------------------------------------------
FilenameField::FilenameField()
{
Type = FIELD_FILENAME;
}
//---------------------------------------------------------------------------
int FilenameField::Compare(Field *Entry)
{
if (!Entry) return -1;
if (Entry->GetType() != GetType()) return 0;
CFStringRef compareString = ((StringField*)Entry)->GetString();
if (!String && !compareString) return 0;
if (!String && compareString) return 1;
if (!compareString) return -1;
return CFStringCompare(String, compareString, 0);
}
Field *FilenameField::Clone(Table *pTable)
{
FilenameField *clone = new FilenameField(String);
clone->Pos = FIELD_CLONE;
clone->ID = ID;
clone->MaxSizeOnDisk = GetDataSize();
return clone;
}

View file

@ -0,0 +1,23 @@
#ifndef NDE_FILENAMEFIELD_H
#define NDE_FILENAMEFIELD_H
/*
Mostly the same as StringField
but this implements OS-dependent string comparisons that make sense for the file system
*/
#include "nde.h"
#include "NDEString.h"
class FilenameField : public StringField
{
protected:
virtual int Compare(Field *Entry);
virtual Field *Clone(Table *pTable);
public:
FilenameField(CFStringRef Str);
FilenameField();
};
#endif

126
Src/nde/osx/IndexField.cpp Normal file
View file

@ -0,0 +1,126 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
IndexField Class
--------------------------------------------------------------------------- */
#include "nde.h"
//---------------------------------------------------------------------------
IndexField::IndexField(unsigned char id, int Pos, int type, CFStringRef FieldName)
{
InitField();
Type = FIELD_INDEX;
Name = (CFStringRef)CFRetain(FieldName);
ID = id;
Position = Pos;
DataType = type;
}
//---------------------------------------------------------------------------
void IndexField::InitField(void)
{
index = 0;
Type = FIELD_INDEX;
Name = NULL;
ID = 0;
Position = -1;
DataType = FIELD_UNKNOWN;
}
//---------------------------------------------------------------------------
IndexField::IndexField()
{
InitField();
}
//---------------------------------------------------------------------------
IndexField::~IndexField()
{
if (Name)
CFRelease(Name);
delete index;
}
//---------------------------------------------------------------------------
void IndexField::ReadTypedData(const uint8_t *data, size_t len)
{
unsigned char c;
int pos=0;
CHECK_INT(len);
Position = GET_INT(); pos += 4;
CHECK_INT(len);
DataType = GET_INT(); pos += 4;
CHECK_CHAR(len);
c = GET_CHAR(); pos++;
if (c)
{
CHECK_BIN(len, c);
if (Name)
CFRelease(Name);
Name = CFStringCreateWithBytes(kCFAllocatorDefault, data+pos, c, kCFStringEncodingUTF8, false);
}
}
//---------------------------------------------------------------------------
void IndexField::WriteTypedData(uint8_t *data, size_t len)
{
int pos=0;
CHECK_INT(len);
PUT_INT(Position); pos += 4;
CHECK_INT(len);
PUT_INT(DataType); pos += 4;
CHECK_CHAR(len);
if (Name)
{
CFIndex lengthRequired=0;
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, NULL, 0, &lengthRequired);
CHECK_BIN(len, lengthRequired+1);
PUT_CHAR(lengthRequired); pos++;
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, data+pos, lengthRequired, 0);
}
}
//---------------------------------------------------------------------------
CFStringRef IndexField::GetIndexName(void)
{
return Name;
}
//---------------------------------------------------------------------------
size_t IndexField::GetDataSize(void)
{
if (Name)
{
CFIndex lengthRequired=0;
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, NULL, 0, &lengthRequired);
return lengthRequired+9;
}
else
return 9;
}
//---------------------------------------------------------------------------
int IndexField::Compare(Field * /*Entry*/)
{
return 0;
}
//---------------------------------------------------------------------------
int IndexField::TranslateToIndex(int Id, IndexField *toindex)
{
if (index && toindex && toindex->index)
return index->TranslateIndex(Id, toindex->index);
return -1;
}

37
Src/nde/osx/IndexField.h Normal file
View file

@ -0,0 +1,37 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
IndexField Class Prototypes
--------------------------------------------------------------------------- */
#ifndef __INDEXFIELD_H
#define __INDEXFIELD_H
class IndexField : public Field
{
public:
IndexField(unsigned char id, int Pos, int type, CFStringRef FieldName);
IndexField();
~IndexField();
virtual void ReadTypedData(const uint8_t *, size_t len);
virtual void WriteTypedData(uint8_t *, size_t len);
virtual size_t GetDataSize(void);
virtual int Compare(Field *Entry);
void InitField(void);
CFStringRef GetIndexName(void);
int TranslateToIndex(int Id, IndexField *index);
Index *index; // TODO: make protected
protected:
int Position;
int DataType;
CFStringRef Name;
};
#endif

170
Src/nde/osx/IndexRecord.cpp Normal file
View file

@ -0,0 +1,170 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
IndexRecord Class
--------------------------------------------------------------------------- */
#include "nde.h"
#include <stdio.h>
IndexRecord::IndexRecord(int RecordPos, int insertionPoint, VFILE *TableHandle, Table *ParentTable)
{
InsertionPoint = insertionPoint;
if (RecordPos != 0)
{
int n=0;
uint32_t ThisPos = RecordPos;
while (ThisPos)
{
if (n >= 128)
break;
Vfseek(TableHandle, ThisPos, SEEK_SET);
Field Entry (ThisPos);
Field *TypedEntry = Entry.ReadField(ParentTable, ThisPos, &ThisPos);
if (!TypedEntry) break; // some db error?
AddField(TypedEntry);
// ThisPos = TypedEntry->GetNextFieldPos();
n++;
}
}
}
void IndexRecord::BuildCollaboration()
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
IndexField *p = (IndexField *)*itr;
if (p->next)
p->index->Colaborate((IndexField *)p->next);
else
p->index->Colaborate((IndexField *)*Fields.begin());
}
}
bool IndexRecord::NeedFix()
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
IndexField *p = (IndexField *)*itr;
if (p->index->NeedFix())
return true;
}
return false;
}
#ifdef _WIN32
IndexField *IndexRecord::GetIndexByName(const wchar_t *name)
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
IndexField *p = (IndexField *)*itr;
if (!_wcsicmp(p->GetIndexName(), name))
return p;
}
return NULL;
}
#else
IndexField *IndexRecord::GetIndexByName(CFStringRef name)
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
IndexField *p = (IndexField *)*itr;
if (CFStringCompare(p->GetIndexName(), name, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
return p;
}
return NULL;
}
#endif
bool IndexRecord::CheckIndexing(int v)
{
int i = v;
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
IndexField *p = (IndexField *)*itr;
v = p->index->GetCooperative(v);
}
return v == i;
}
void IndexRecord::SetModified(BOOL modifiedVal)
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
IndexField *p = (IndexField *)*itr;
p->index->Modified = modifiedVal;
}
}
Field *RecordBase::GetField(unsigned char ID)
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
IndexField *p = (IndexField *)*itr;
if (p->GetFieldId() == ID)
return p;
}
return NULL;
}
void RecordBase::AddField(Field *field)
{
if (!field) return;
if (GetField(field->ID))
return;
Fields.push_back(field);
}
int IndexRecord::WriteFields(Table *ParentTable)
{
Field *previous = 0;
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
IndexField *p = (IndexField *)*itr;
p->WriteField(ParentTable, previous, (Field *)p->next);
previous = p;
}
return WriteIndex(ParentTable);
}
int IndexRecord::WriteIndex(Table *ParentTable)
{
int P=0;
if (!Fields.empty())
P=(*Fields.begin())->GetFieldPos();
return ParentTable->index->Update(INDEX_RECORD_NUM, P, this, FALSE);
}
void RecordBase::RemoveField(Field *field)
{
if (!field)
return;
Fields.erase(field);
delete field;
}
void IndexRecord::WalkFields(FieldsWalker callback, void *context)
{
if (callback)
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
if (!callback(this, *itr, context))
break;
}
}
}

19
Src/nde/osx/IndexRecord.h Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include <stdio.h>
#include "Record.h"
#include "../nu/PtrDeque2.h"
class IndexRecord : public RecordBase
{
public:
IndexRecord(int RecordPos, int insertionPoint, VFILE *FileHandle,Table *p);
void BuildCollaboration();
bool NeedFix();
IndexField *GetIndexByName(const wchar_t *name);
int GetColumnCount() { return Fields.size() - 1; }
bool CheckIndexing(int v);
int WriteFields(Table *ParentTable);
int WriteIndex(Table *ParentTable);
typedef bool (*FieldsWalker)(IndexRecord *record, Field *entry, void *context);
void WalkFields(FieldsWalker callback, void *context);
};

1018
Src/nde/osx/IntegerField.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,93 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
IntegerField Class Prototypes
--------------------------------------------------------------------------- */
#ifndef __INTEGERFIELD_H
#define __INTEGERFIELD_H
#include <bfc/platform/types.h>
class TimeParse {
public:
int is_relative; // ago/after/before used
int absolute_datetime; // if not is_relative, this is the date/time, otherwise it's the resulting date/time if the query was ran now
int absolute_hasdate; // if not, use only the time portion of absolute_datetime, the rest is now
int absolute_hastime; // if not, use only the date portion of absolute_datetime, the rest is now
int relative_year; // -1 = this year
int relative_month; // -1 = this month
int relative_day; // -1 = this day, -2 = this week
int relative_hour; // -1 = this hour
int relative_min; // -1 = this minute
int relative_sec; // -1 = this second
int relative_kwday; // not used(-1), 0 to 6 for sunday to saturday, yesterday(7), today(8), tomorrow(9)
int offset_value; // timeago/offsetby numerical edit field
int offset_what; // not used(-1) years(0), months(1), weeks(2), days(3), hours(4), minutes(5), seconds(6)
int offset_whence; // not used(-1), after(0), ago/before(1)
int offset_used; // if 1, 'time ago' / 'offset by' should be checked
};
class IntegerField : public Field
{
protected:
virtual void ReadTypedData(const uint8_t *, size_t len);
virtual void WriteTypedData(uint8_t *, size_t len);
virtual size_t GetDataSize(void);
virtual int Compare(Field *Entry);
virtual bool ApplyFilter(Field *Data, int op);
void InitField(void);
int Value;
enum {
WHAT_YEARS,
WHAT_MONTHS,
WHAT_WEEKS,
WHAT_DAYS,
WHAT_HOURS,
WHAT_MINUTES,
WHAT_SECONDS,
};
enum {
FROM_BARE,
FROM_AGO,
FROM_SINCE,
};
public:
~IntegerField();
IntegerField(int);
IntegerField();
int GetValue(void);
void SetValue(int);
int ApplyConversion(const char *format, TimeParse *tp=NULL);
static int LookupToken(CFStringRef t);
};
class DateTimeField : public IntegerField {
public:
DateTimeField();
DateTimeField(int Val);
virtual ~DateTimeField();
};
class LengthField : public IntegerField {
public:
LengthField();
LengthField(int Val);
virtual ~LengthField();
};
#endif

936
Src/nde/osx/Query.cpp Normal file
View file

@ -0,0 +1,936 @@
#include "nde.h"
#include "NDEString.h"
#include "Query.h"
//---------------------------------------------------------------------------
BOOL Scanner::Query(const char *query)
{
if (!query) return FALSE;
if (last_query) CFRelease(last_query);
last_query = CFStringCreateWithBytes(NULL, (const uint8_t *)query, strlen(query), kCFStringEncodingUTF32, false);
RemoveFilters();
in_query_parser = 1;
BOOL r = Query_Parse(query);
if (r == FALSE)
{
if (!disable_date_resolution) RemoveFilters();
last_query_failed = TRUE;
}
in_query_parser = 0;
Query_CleanUp();
return r & CheckFilters();
}
CFStringRef Scanner::GetLastQuery()
{
return last_query;
}
typedef struct
{
CFStringRef token;
int tid;
} tokenstruct;
tokenstruct Tokens[] = // Feel free to add more...
{
{CFSTR("AND"), TOKEN_AND },
{CFSTR("OR"), TOKEN_OR },
{CFSTR("HAS"), TOKEN_CONTAINS },
{CFSTR("NOTHAS"),TOKEN_NOTCONTAINS},
{CFSTR("BEGINS"), TOKEN_BEGINS },
{CFSTR("ENDS"), TOKEN_ENDS },
{CFSTR("ISEMPTY"), TOKEN_ISEMPTY},
{CFSTR("ISNOTEMPTY"),TOKEN_ISNOTEMPTY},
{CFSTR("LIKE"), TOKEN_LIKE},
{CFSTR("BEGINSLIKE"), TOKEN_BEGINSLIKE},
};
typedef struct
{
int Op;
int Level;
} OpLevel;
static int Query_ParseLength(CFStringRef str)
{
int x;
CFArrayRef array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(":"));
if (array)
{
CFIndex count = CFArrayGetCount(array);
if (count == 2)
{
CFStringRef t1 = (CFStringRef)CFArrayGetValueAtIndex(array, 0);
CFStringRef t2 = (CFStringRef)CFArrayGetValueAtIndex(array, 1);
x = CFStringGetIntValue(t1) * 60 + CFStringGetIntValue(t2);
CFRelease(array);
return x;
}
if (count == 3)
{
CFStringRef t1 = (CFStringRef)CFArrayGetValueAtIndex(array, 0);
CFStringRef t2 = (CFStringRef)CFArrayGetValueAtIndex(array, 1);
CFStringRef t3 = (CFStringRef)CFArrayGetValueAtIndex(array, 2);
x = CFStringGetIntValue(t1) * 60 * 60 + CFStringGetIntValue(t2) * 60 + CFStringGetIntValue(t3);
CFRelease(array);
return x;
}
CFRelease(array);
}
return CFStringGetIntValue(str);;
}
/*
our state machine
&, |
----------<-------------------------<----------------------<-----------
| |
v ID (Col) =, >, <... ID / Data / [f] ) |
---->(0) ----->-----> (1) ------>-----> (2) ------>------> (3) ------>-----> (4) <--
| |^ \isempty------------->------------/ |^ | |
| !( || ||---- | ) |
--<-- ---------<---------------------------<-------------<-| | -->--
&, | v [f] |
-->--
*/
//---------------------------------------------------------------------------
BOOL Scanner::Query_Parse(const char *query)
{
const char *p = query; // pointer on next token to read
size_t size;
int state = 0;
int pcount = 0;
VListEntry<OpLevel> *entry;
if (pstack.GetNElements() > 0)
Query_CleanUp();
while (1)
{
p = Query_EatSpace(p);
int t = Query_GetNextToken(p, &size, &token);
if (t == TOKEN_UNKNOWN)
{
Query_SyntaxError((int)(p-query));
return FALSE;
}
if (t == TOKEN_EOQ)
break;
switch (state)
{
case 0:
switch (t)
{
case TOKEN_PAROPEN:
state = 0;
// check too many parenthesis open
if (pcount == 255)
{
Query_SyntaxError((int)(p-query)); // should not be _syntax_ error
return FALSE;
}
// up one level
pcount++;
break;
case TOKEN_NOT:
// push not in this level
OpLevel o;
o.Op = FILTER_NOT;
o.Level = pcount;
entry = new VListEntry<OpLevel>;
entry->SetVal(o);
pstack.AddEntry(entry, TRUE);
state = 0;
break;
case TOKEN_IDENTIFIER:
state = 1;
// create filter column
if (AddFilterByName(token, NULL, FILTER_NONE) == ADDFILTER_FAILED)
{
Query_SyntaxError((int)(p-query));
return FALSE;
}
break;
default:
Query_SyntaxError((int)(p-query));
return FALSE;
}
break;
case 1:
switch (t)
{
case TOKEN_EQUAL:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_EQUALS);
break;
}
case TOKEN_ABOVE:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_ABOVE);
break;
}
case TOKEN_BELOW:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_BELOW);
break;
}
case TOKEN_CONTAINS:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_CONTAINS);
break;
}
case TOKEN_NOTCONTAINS:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_NOTCONTAINS);
break;
}
case TOKEN_AOREQUAL:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_ABOVEOREQUAL);
break;
}
case TOKEN_BOREQUAL:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_BELOWOREQUAL);
break;
}
case TOKEN_NOTEQUAL:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_NOTEQUALS);
break;
}
case TOKEN_BEGINS:
{
state = 2;
Filter *f = GetLastFilter();
f->SetOp(FILTER_BEGINS);
}
break;
case TOKEN_ENDS:
{
state = 2;
Filter *f = GetLastFilter();
f->SetOp(FILTER_ENDS);
}
break;
case TOKEN_LIKE:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_LIKE);
break;
}
case TOKEN_BEGINSLIKE:
{
state = 2;
// set filter op
Filter *f = GetLastFilter();
f->SetOp(FILTER_BEGINSLIKE);
break;
}
case TOKEN_ISNOTEMPTY:
case TOKEN_ISEMPTY:
{
state = 3;
Filter *f = GetLastFilter();
f->SetOp(t==TOKEN_ISEMPTY ? FILTER_ISEMPTY : FILTER_ISNOTEMPTY);
// pop all operators in this level beginning by the last inserted
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
while (entry)
{
if (entry->GetVal().Level == pcount)
{
AddFilterOp(entry->GetVal().Op);
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
pstack.RemoveEntry(entry);
entry = _entry;
}
else
break;
}
}
break;
default:
Query_SyntaxError((int)(p-query));
return FALSE;
}
break;
case 2:
if (t == TOKEN_SQBRACKETOPEN)
{
state = 3;
const char *s = strchr(p, ']');
if (!s)
{
Query_SyntaxError((int)(p-query));
return FALSE;
}
p = Query_EatSpace(p);
if (*p == '[') p++;
CFStringRef format = CFStringCreateWithBytes(NULL, (const uint8_t *)p, (s-p), kCFStringEncodingUTF32, false);
Filter *f = GetLastFilter();
int id = f->GetId();
ColumnField *c = GetColumnById(id);
int tt = c ? c->GetDataType() : -1;
if (disable_date_resolution || !c || (tt != FIELD_INTEGER && tt != FIELD_DATETIME && tt != FIELD_LENGTH && tt != FIELD_BOOLEAN))
{
if (disable_date_resolution)
{
StringField *field = (StringField *)f->Data();
if (!field)
{
// format was used without a value, assume value is 0
f->SetData(new StringField(CFSTR("")));
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
while (entry)
{
if (entry->GetVal().Level == pcount)
{
AddFilterOp(entry->GetVal().Op);
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
pstack.RemoveEntry(entry);
entry = _entry;
}
else
break;
}
field = (StringField*)f->Data();
}
field->SetNDEString(format);
if (format) CFRelease(format);
p = s+1;
continue;
}
if (format) CFRelease(format);
Query_SyntaxError((int)(p-query));
return FALSE;
}
IntegerField *field = (IntegerField *)f->Data();
if (!field)
{
// format was used without a value, assume value is 0
f->SetData(new IntegerField(0));
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
while (entry)
{
if (entry->GetVal().Level == pcount)
{
AddFilterOp(entry->GetVal().Op);
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
pstack.RemoveEntry(entry);
entry = _entry;
}
else
break;
}
field = (IntegerField *)f->Data();
}
// TODO: make sure this is safe (that p and s havn't been iterated)
char *temp_format = (char *)malloc((s-p+1));
strncpy(temp_format, p, s-p);
temp_format[s-p] = 0;
int r = field->ApplyConversion(temp_format);
free(temp_format);
ndestring_release(format);
if (!r)
{
Query_SyntaxError((int)(p-query));
return FALSE;
}
p = s+1;
continue;
}
// switch (t) {
// case TOKEN_IDENTIFIER:
else // JF> we make this relaxed, so anything is valid as a value
{
state = 3;
// set filter data
Filter *f = GetLastFilter();
int id = f->GetId();
ColumnField *c = GetColumnById(id);
switch (c ? c->GetDataType() : -1)
{
case FIELD_DATETIME:
if (disable_date_resolution)
goto field_string_override;
case FIELD_LENGTH:
{
int i;
IntegerField *i_f = new IntegerField();
i = Query_ParseLength(token);
i_f->SetValue(i);
f->SetData(i_f);
}
break;
case FIELD_BOOLEAN:
case FIELD_INTEGER:
{
int i;
IntegerField *i_f = new IntegerField();
i = CFStringGetIntValue(token);
i_f->SetValue(i);
f->SetData(i_f);
}
break;
case FIELD_INT64:
{
int64_t i;
Int64Field *i_f = new Int64Field();
#ifdef _WIN32
i = _wtoi64(token); // todo: Replace with own conversion and error checking
#else
i = CFStringGetIntValue(token); // TODO!!! 64bit integer here ... maybe use CFNumberFormatterCreateNumberFromString but it's a lot of overhead
#endif
i_f->SetValue(i);
f->SetData(i_f);
}
break;
case FIELD_FILENAME:
{
FilenameField *s_f = new FilenameField();
s_f->SetNDEString(token);
f->SetData(s_f);
}
break;
case FIELD_STRING:
field_string_override:
{
StringField *s_f = new StringField();
s_f->SetNDEString(token);
f->SetData(s_f);
}
break;
default:
Query_SyntaxError((int)(p-query));
return FALSE;
break;
}
// pop all operators in this level beginning by the last inserted
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
while (entry)
{
if (entry->GetVal().Level == pcount)
{
AddFilterOp(entry->GetVal().Op);
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
pstack.RemoveEntry(entry);
entry = _entry;
}
else
break;
}
break;
}
// default:
// Query_SyntaxError(p-query);
// return FALSE;
// }
break;
case 3:
switch (t)
{
case TOKEN_SQBRACKETOPEN:
{
const char *s = strchr(p, ']');
if (!s)
{
Query_SyntaxError((int)(p-query));
return FALSE;
}
p = Query_EatSpace(p);
if (*p == '[') p++;
CFStringRef format = CFStringCreateWithBytes(NULL, (const uint8_t *)p, (s-p), kCFStringEncodingUTF32, false);
Filter *f = GetLastFilter();
int id = f->GetId();
ColumnField *c = GetColumnById(id);
int tt = c ? c->GetDataType() : -1;
if (disable_date_resolution || !c || (tt != FIELD_INTEGER && tt != FIELD_DATETIME && tt != FIELD_LENGTH && tt != FIELD_BOOLEAN))
{
if (disable_date_resolution)
{
StringField *field = (StringField *)f->Data();
if (!field)
{
// format was used without a value, assume value is 0
f->SetData(new StringField(CFSTR("")));
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
while (entry)
{
if (entry->GetVal().Level == pcount)
{
AddFilterOp(entry->GetVal().Op);
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
pstack.RemoveEntry(entry);
entry = _entry;
}
else
break;
}
field = (StringField *)f->Data();
}
field->SetNDEString(format);
if (format) CFRelease(format);
p = s+1;
continue;
}
if (format) CFRelease(format);
Query_SyntaxError((int)(p-query));
return FALSE;
}
IntegerField *field = (IntegerField *)f->Data();
if (!field)
{
// format was used without a value, assume value is 0
f->SetData(new IntegerField(0));
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
while (entry)
{
if (entry->GetVal().Level == pcount)
{
AddFilterOp(entry->GetVal().Op);
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
pstack.RemoveEntry(entry);
entry = _entry;
}
else
break;
}
field = (IntegerField *)f->Data();
}
// TODO: make sure this is safe (that p and s havn't been iterated)
char *temp_format = (char *)malloc((s-p+1));
strncpy(temp_format, p, s-p);
temp_format[s-p] = 0;
int r = field->ApplyConversion(temp_format);
free(temp_format);
ndestring_release(format);
if (!r)
{
Query_SyntaxError((int)(p-query));
return FALSE;
}
p = s+1;
continue;
}
break;
case TOKEN_PARCLOSE:
state = 4;
// check parenthesis count
if (pcount == 0)
{
Query_SyntaxError((int)(p-query));
return FALSE;
}
// down one level
pcount--;
// pop all operators in this level, beginning by the last inserted
while (entry)
{
if (entry->GetVal().Level == pcount)
{
AddFilterOp(entry->GetVal().Op);
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
pstack.RemoveEntry(entry);
entry = _entry;
}
else
break;
}
break;
case TOKEN_AND:
{
state = 0;
// push and
OpLevel o;
o.Op = FILTER_AND;
o.Level = pcount;
entry = new VListEntry<OpLevel>;
entry->SetVal(o);
pstack.AddEntry(entry, TRUE);
break;
}
case TOKEN_OR:
{
state = 0;
// push or
OpLevel o;
o.Op = FILTER_OR;
o.Level = pcount;
entry = new VListEntry<OpLevel>;
entry->SetVal(o);
pstack.AddEntry(entry, TRUE);
break;
}
default:
Query_SyntaxError((int)(p-query));
return FALSE;
}
break;
case 4:
switch (t)
{
case TOKEN_AND:
{
state = 0;
// push and
OpLevel o;
o.Op = FILTER_AND;
o.Level = pcount;
entry = new VListEntry<OpLevel>;
entry->SetVal(o);
pstack.AddEntry(entry, TRUE);
break;
}
case TOKEN_OR:
{
state = 0;
// push or
OpLevel o;
o.Op = FILTER_OR;
o.Level = pcount;
entry = new VListEntry<OpLevel>;
entry->SetVal(o);
pstack.AddEntry(entry, TRUE);
break;
}
case TOKEN_PARCLOSE:
state = 4;
// check parenthesis count
if (pcount == 0)
{
Query_SyntaxError((int)(p-query));
return FALSE;
}
// down one level
pcount--;
// pop all operators in this level, beginning by the last inserted
while (entry)
{
if (entry->GetVal().Level == pcount)
{
AddFilterOp(entry->GetVal().Op);
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
pstack.RemoveEntry(entry);
entry = _entry;
}
else
break;
}
break;
default:
Query_SyntaxError((int)(p-query));
return FALSE;
}
break;
default:
// Ahem... :/
break;
}
p += size;
}
if (pcount > 0)
{
Query_SyntaxError((int)(p-query));
return FALSE;
}
return TRUE;
}
//---------------------------------------------------------------------------
void Scanner::Query_SyntaxError(int c)
{
}
//---------------------------------------------------------------------------
void Scanner::Query_CleanUp()
{
while (pstack.GetNElements() > 0)
{
VListEntry<int> *e;
e = (VListEntry<int> *)pstack.GetHead();
pstack.RemoveEntry(e);
}
}
//---------------------------------------------------------------------------
const char *Scanner::Query_EatSpace(const char *p)
{
while (*p && *p == ' ') p++;
return p;
}
//---------------------------------------------------------------------------
const char *Scanner::Query_ProbeNonAlphaNum(const char *p)
{
int inquote=0;
while (*p && (!Query_isControlChar(*p) || (inquote)))
{
if (*p == '\"')
{
if (!inquote)
inquote = 1;
else
return p+1;
}
p++;
}
return p;
}
//---------------------------------------------------------------------------
int Scanner::Query_isControlChar(char p)
{
switch (p)
{
case '&':
case '|':
case '!':
case '(':
case '[':
case ')':
case ']':
case '>':
case '<':
case '=':
case ',':
case ' ':
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
char *Scanner::Query_ProbeAlphaNum(char *p)
{
while (*p && Query_isControlChar(*p)) p++;
return p;
}
//---------------------------------------------------------------------------
char *Scanner::Query_ProbeSpace(char *p)
{
while (*p && *p != ' ') p++;
return p;
}
//---------------------------------------------------------------------------
int Scanner::Query_LookupToken(CFStringRef t)
{
for (int i=0;i<sizeof(Tokens)/sizeof(tokenstruct);i++)
{
if (CFStringCompare(Tokens[i].token, t, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
return Tokens[i].tid;
}
return TOKEN_IDENTIFIER;
}
//---------------------------------------------------------------------------
int Scanner::Query_GetNextToken(const char *p, size_t *size, CFStringRef *_token, int tokentable)
{
int t = TOKEN_EOQ;
const char *startptr = p;
if (!*p) return TOKEN_EOQ;
p = Query_EatSpace(p);
const char *e = Query_ProbeNonAlphaNum(p);
if (e != p) // We have a word
{
if (*_token) CFRelease(*_token);
// check for a quoted string
if (*p == '\"' && e != p+1 && e[-1] == '\"')
{
CFStringRef inner_string = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)(p+1), (e-p-2), kCFStringEncodingUTF8, false);
// escape it (ugh)
CFStringRef escaped_string = CFURLCreateStringByReplacingPercentEscapes(NULL, inner_string, CFSTR(""));
if (escaped_string)
{
*_token = escaped_string;
CFRelease(inner_string);
}
else
{
*_token = inner_string;
}
}
else
{
*_token = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)p, (e-p), kCFStringEncodingUTF8, false);
}
switch (tokentable)
{
case -1:
t = TOKEN_IDENTIFIER;
break;
case 0:
t = Query_LookupToken(*_token);
break;
case 1:
t = IntegerField::LookupToken(*_token);
}
p = e;
}
else // We have a symbol
{
switch (*p)
{
case '&':
if (*(p+1) == '&') p++;
t = TOKEN_AND;
break;
case '|':
if (*(p+1) == '|') p++;
t = TOKEN_OR;
break;
case '!':
if (*(p+1) == '=')
{
p++;
t = TOKEN_NOTEQUAL;
break;
}
t = TOKEN_NOT;
break;
case '(':
t = TOKEN_PAROPEN;
break;
case ')':
t = TOKEN_PARCLOSE;
break;
case '[':
t = TOKEN_SQBRACKETOPEN;
break;
case ']':
t = TOKEN_SQBRACKETCLOSE;
break;
case ',':
t = TOKEN_COMMA;
break;
case '>':
if (*(p+1) == '=')
{
p++;
t = TOKEN_AOREQUAL;
break;
}
if (*(p+1) == '<')
{
p++;
t = TOKEN_NOTEQUAL;
break;
}
t = TOKEN_ABOVE;
break;
case '<':
if (*(p+1) == '=')
{
p++;
t = TOKEN_BOREQUAL;
break;
}
if (*(p+1) == '>')
{
p++;
t = TOKEN_NOTEQUAL;
break;
}
t = TOKEN_BELOW;
break;
case '=':
if (*(p+1) == '>')
{
p++;
t = TOKEN_AOREQUAL;
break;
}
if (*(p+1) == '<')
{
p++;
t = TOKEN_BOREQUAL;
break;
}
if (*(p+1) == '!')
{
p++;
t = TOKEN_NOTEQUAL;
break;
}
if (*(p+1) == '=') p++;
t = TOKEN_EQUAL;
break;
default:
t = TOKEN_UNKNOWN;
break;
}
p++;
}
*size = (int)(p - startptr);
return t;
}

27
Src/nde/osx/Query.h Normal file
View file

@ -0,0 +1,27 @@
#pragma once
#define TOKEN_UNKNOWN -1 // BLAAAAA!!!!!!!!
#define TOKEN_EOQ 0 // End of Query
#define TOKEN_IDENTIFIER 1 // Column name or data to match against
#define TOKEN_EQUAL 2 // =, ==, IS
#define TOKEN_NOTEQUAL 3 // !=, =!, <>, ><
#define TOKEN_BELOW 4 // <
#define TOKEN_ABOVE 5 // >
#define TOKEN_BOREQUAL 6 // <=, =<
#define TOKEN_AOREQUAL 7 // >=, =>
#define TOKEN_NOT 8 // !, NOT
#define TOKEN_AND 9 // &, &&, AND
#define TOKEN_OR 10 // |, ||, OR
#define TOKEN_PAROPEN 11 // (
#define TOKEN_PARCLOSE 12 // )
#define TOKEN_CONTAINS 13 // HAS
#define TOKEN_BEGINS 14 // string starts with...
#define TOKEN_ENDS 15 // string ends with...
#define TOKEN_LIKE 16 // string is nearly (excluding "the " and whitespace etc)
#define TOKEN_ISEMPTY 17 // field does not exists
#define TOKEN_SQBRACKETOPEN 18 // [
#define TOKEN_SQBRACKETCLOSE 19 // ]
#define TOKEN_COMMA 20 // ,
#define TOKEN_NOTCONTAINS 21 // NOTHAS
#define TOKEN_ISNOTEMPTY 22 // field does not exists
#define TOKEN_BEGINSLIKE 23 // string is nearly starts with (excluding "the " and whitespace etc)

138
Src/nde/osx/Record.cpp Normal file
View file

@ -0,0 +1,138 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
Record Class
--------------------------------------------------------------------------- */
//#include "record.h"
#include "nde.h"
#include <stdio.h>
void RecordBase::Retain()
{
ref_count++;
}
void RecordBase::Release()
{
if (--ref_count == 0)
delete this;
}
RecordBase::RecordBase()
{
ref_count = 1;
InsertionPoint = 0;
}
//---------------------------------------------------------------------------
Record::Record(int RecordPos, int insertionPoint, VFILE *TableHandle, Table *ParentTable)
{
InsertionPoint = insertionPoint;
Record *columns = ParentTable->GetColumns();
int max=columns ? columns->Fields.size() : 128;
int n=0;
if (RecordPos != 0)
{
uint32_t ThisPos = RecordPos;
while (ThisPos)
{
if (n >= max)
break;
Vfseek(TableHandle, ThisPos, SEEK_SET);
Field Entry (ThisPos);
Field *TypedEntry = Entry.ReadField(ParentTable, ThisPos, &ThisPos);
if (!TypedEntry) break; // some db error?
AddField(TypedEntry);
n++;
}
}
}
//---------------------------------------------------------------------------
RecordBase::~RecordBase()
{
Fields.deleteAll();
}
#ifdef _WIN32
ColumnField *Record::GetColumnByName(const wchar_t *name)
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
ColumnField *p = (ColumnField *)*itr;
if (!_wcsicmp(p->GetFieldName(), name))
return p;
}
return NULL;
}
#elif defined(__APPLE__)
ColumnField *Record::GetColumnByName(CFStringRef name)
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
ColumnField *p = (ColumnField *)*itr;
if (CFStringCompare(p->GetFieldName(), name, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
return p;
}
return NULL;
}
#endif
//---------------------------------------------------------------------------
int Record::WriteFields(Table *ParentTable, int RecordIndex)
{
Field *previous = 0;
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
Field *p = *itr;
p->WriteField(ParentTable, previous, (Field *)p->next);
previous = p;
}
return WriteIndex(ParentTable, RecordIndex);
}
//---------------------------------------------------------------------------
int Record::WriteIndex(Table *ParentTable, int RecordIndex)
{
int P=0;
if (RecordIndex == NEW_RECORD)
RecordIndex = ParentTable->index->Insert(InsertionPoint);
if (!Fields.empty())
{
Field *f = *Fields.begin();
P=f->GetFieldPos();
}
return ParentTable->index->Update(RecordIndex, P, this, FALSE);
}
//---------------------------------------------------------------------------
void Record::Delete(Table *ParentTable, int RecordIndex)
{
ParentTable->index->Delete(RecordIndex, ParentTable->index->Get(RecordIndex), this);
}
void Record::WalkFields(FieldsWalker callback, void *context)
{
if (callback)
{
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
{
if (!callback(this, *itr, context))
break;
}
}
}

50
Src/nde/osx/Record.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#include "field.h"
#include "Vfs.h"
#include <stdio.h>
#include "../nu/PtrMap.h"
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
class ColumnField;
class RecordBase
{
public:
RecordBase();
virtual ~RecordBase();
Field *GetField(unsigned char ID);
void Retain();
void Release();
void RemoveField(Field *field);
void AddField(Field *field);
protected:
void Undelete(void);
int InsertionPoint; // TODO: benski> might be able to pass this into WriteFields/WriteIndex
int ref_count;
typedef nu::PtrDeque2<Field> FieldList;
FieldList Fields;
};
class Record : public RecordBase
{
public:
Record(int RecordPos, int insertionPoint, VFILE *FileHandle,Table *p);
bool InCache() { return ref_count > 1; }
#ifdef __APPLE__
ColumnField *GetColumnByName(CFStringRef name);
#else
ColumnField *GetColumnByName(const wchar_t *name);
#endif
int WriteFields(Table *ParentTable, int RecordIndex);
int WriteIndex(Table *ParentTable, int RecordIndex);
void Delete(Table *ParentTable, int RecordIndex);
typedef bool (*FieldsWalker)(Record *record, Field *entry, void *context);
NDE_API void WalkFields(FieldsWalker callback, void *context);
};

1283
Src/nde/osx/Scanner.cpp Normal file

File diff suppressed because it is too large Load diff

210
Src/nde/osx/Scanner.h Normal file
View file

@ -0,0 +1,210 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
Scanner Class Prototypes
--------------------------------------------------------------------------- */
#ifndef __SCANNER_H
#define __SCANNER_H
#include "record.h"
#include "Table.h"
#include "index.h"
#include "../nu/Vector.h"
#include "../nu/ValueSet.h"
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
class Table;
class Index;
#pragma warning( disable: 4251 )
class Scanner;
class Record;
class Scanner : public LinkedListEntry
{
public:
Record *GetRecord(int Idx);
Scanner(Table *parentTable);
void IndexModified(void);
Index *GetIndex() { return index; }
Index *index; // TODO: make protected
protected:
~Scanner();
Table *pTable;
BOOL iModified;
typedef Vector<StringField *> SearchStrings;
SearchStrings search_strings;
typedef ValueSet<unsigned char> SearchFields;
SearchFields search_fields;
bool search_any;
void GetCurrentRecord(void);
bool MatchFilters(void);
bool MatchSearches();
bool MatchSearch(const SearchFields &fields, StringField *search_field);
//BOOL MatchJoins(void);
int CheckFilters(void);
void CacheLastLocate(int Id, int From, Field *field, Index *i, int j);
#ifdef _WIN32
static int Query_LookupToken(const wchar_t *token);
#else
static int Query_LookupToken(CFStringRef token);
#endif
void Query_CleanUp(void);
void Query_SyntaxError(int c);
public:
#ifdef _WIN32
static int Query_GetNextToken(const wchar_t *p, int *size, wchar_t **token, int tokentable=0);
static const wchar_t *Query_EatSpace(const wchar_t *p);
static wchar_t *Query_ProbeSpace(wchar_t *p);
static const wchar_t *Query_ProbeNonAlphaNum(const wchar_t *p);
static wchar_t *Query_ProbeAlphaNum(wchar_t *p);
static int Query_isControlChar(wchar_t p);
BOOL Query(const wchar_t *query);
BOOL Query_Parse(const wchar_t *query);
#else
static int Query_GetNextToken(const char *p, size_t *size, CFStringRef *token, int tokentable=0);
static const char *Query_EatSpace(const char *p);
static char *Query_ProbeSpace(char *p);
static const char *Query_ProbeNonAlphaNum(const char *p);
static char *Query_ProbeAlphaNum(char *p);
static int Query_isControlChar(char p);
BOOL Query(const char *query);
BOOL Query_Parse(const char *query);
#endif
#ifdef _WIN32
const wchar_t *GetLastQuery();
#elif defined(__APPLE__)
CFStringRef GetLastQuery();
#endif
public://fucko: protected
//String token;
LinkedList pstack;
#ifdef _WIN32
wchar_t *token;
#else
CFStringRef token;
#endif
#ifdef _WIN32
wchar_t *last_query;
#elif defined(__APPLE__)
CFStringRef last_query;
#endif
int last_query_failed;
protected:
Record *CurrentRecord;
int CurrentRecordIdx;
LinkedList FilterList;
Index *lastLocateIndex;
int lastLocateIdx;
Field *lastLocateFieldClone;
int lastLocateFrom;
int lastLocateId;
BOOL Edition;
int ResultPtr;
BOOL FiltersOK;
public:
bool MatchFilter(Filter *filter);
typedef bool (*FilterWalker)(Scanner *scanner, Filter *filter, void *context);
void WalkFilters(FilterWalker walker, void *context);
#ifdef _WIN32
ColumnField *GetColumnByName(const wchar_t *FieldName);
#else
ColumnField *GetColumnByName(CFStringRef FieldName);
#endif
ColumnField *GetColumnById(unsigned char id);
#ifdef _WIN32
Field *NewFieldByName(const wchar_t *fieldName, unsigned char Perm);
#else
Field *NewFieldByName(CFStringRef fieldName, unsigned char Perm);
#endif
Field *NewFieldById(unsigned char Id, unsigned char Perm);
void DeleteField(Field *field);
#ifdef _WIN32
void DeleteFieldByName(const wchar_t *name);
#else
void DeleteFieldByName(CFStringRef name);
#endif
void DeleteFieldById(unsigned char Id);
void Cancel(void);
void Insert(void);
void Edit(void);
void Post(void);
void Delete(void);
#ifdef _WIN32
Field *GetFieldByName(const wchar_t *FieldName);
#else
Field *GetFieldByName(CFStringRef FieldName);
#endif
Field *GetFieldById(unsigned char Id);
void First(int *killswitch=0);
void Last(int *killswitch=0);
int Next(int *killswitch=0);
int Previous(int *killswitch=0);
BOOL Eof(void);
BOOL Bof(void);
void New(void);
int GetRecordsCount(void);
void GetRecordById(int Id, BOOL checkFilters=TRUE);
int GetRecordId(void);
void Sync(void);
#ifdef _WIN32
BOOL LocateByName(const wchar_t *column, int From, Field *field, int *nskip=NULL);
#else
BOOL LocateByName(CFStringRef column, int From, Field *field, int *nskip=NULL);
#endif
BOOL LocateById(int Id, int From, Field *field, int *nskip=NULL);
BOOL LocateByIdEx(int Id, int From, Field *field, int *nskip, int comp_mode);
// Filters
#ifdef _WIN32
int AddFilterByName(const wchar_t *name, Field *Data, unsigned char Op);
#else
int AddFilterByName(CFStringRef name, Field *Data, unsigned char Op);
#endif
int AddFilterById(unsigned char Id, Field *Data, unsigned char Op);
int AddFilterOp(unsigned char Op);
void RemoveFilters(void);
Filter *GetLastFilter(void);
#ifdef _WIN32
BOOL SetWorkingIndexByName(const wchar_t *desc);
#else
BOOL SetWorkingIndexByName(CFStringRef desc);
#endif
BOOL SetWorkingIndexById(unsigned char Id);
#ifdef _WIN32
void Search(const wchar_t *search_string);
#endif
BOOL HasIndexChanged(void) { return iModified; }
void ClearDirtyBit(void);
float FragmentationLevel(void);
Table *GetTable();
int in_query_parser;
int disable_date_resolution;
};
#endif

297
Src/nde/osx/StringField.cpp Normal file
View file

@ -0,0 +1,297 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
StringField Class
Mac OS X (CFStringRef) implementation
--------------------------------------------------------------------------- */
#include "../nde.h"
#include "StringField.h"
//---------------------------------------------------------------------------
StringField::StringField(CFStringRef Str)
{
InitField();
Type = FIELD_STRING;
if (Str)
{
SetNDEString(Str);
}
}
//---------------------------------------------------------------------------
void StringField::InitField(void)
{
Type = FIELD_STRING;
String=0;
}
//---------------------------------------------------------------------------
StringField::StringField()
{
InitField();
}
//---------------------------------------------------------------------------
StringField::~StringField()
{
if (String)
CFRelease(String);
}
//---------------------------------------------------------------------------
void StringField::ReadTypedData(const uint8_t *data, size_t len)
{
unsigned short c;
CHECK_SHORT(len);
c = (unsigned short)(data[0]|(data[1]<<8));
data+=2;
if (c)
{
bool unicode=false;
if (c >= 2 // enough room for BOM
&& (c % 2) == 0) // can't be unicode if it's not an even multiple of 2
{
wchar_t BOM=0;
memcpy(&BOM, data, 2);
if (BOM == 0xFEFF || BOM == 0xFFFE)
{
unicode=true;
}
}
CHECK_BIN(len, c);
if (unicode)
{
if (String)
CFRelease(String);
String = CFStringCreateWithBytes(kCFAllocatorDefault, data, c, kCFStringEncodingUTF16, true);
}
else
{
if (String)
CFRelease(String);
String = CFStringCreateWithBytes(kCFAllocatorDefault, data, c, kCFStringEncodingWindowsLatin1, false);
}
}
}
//---------------------------------------------------------------------------
void StringField::WriteTypedData(uint8_t *data, size_t len)
{
int pos=0;
CHECK_SHORT(len);
if (String)
{
CFIndex lengthRequired=0;
CFStringGetBytes(String, CFRangeMake(0, CFStringGetLength(String)), kCFStringEncodingUTF16, 0, true, NULL, 0, &lengthRequired);
CHECK_BIN(len, lengthRequired+2);
PUT_SHORT(lengthRequired); pos+=2;
CFStringGetBytes(String, CFRangeMake(0, CFStringGetLength(String)), kCFStringEncodingUTF16, 0, true, data+pos, lengthRequired, 0);
}
else
{
PUT_SHORT(0);
}
}
CFStringRef StringField::GetString()
{
return String;
}
void StringField::SetNDEString(CFStringRef Str)
{
if (!Str)
return;
CFStringRef old = String;
String = (CFStringRef)CFRetain(Str);
CFRelease(old);
}
//---------------------------------------------------------------------------
size_t StringField::GetDataSize(void)
{
if (String)
{
CFIndex lengthRequired=0;
CFStringGetBytes(String, CFRangeMake(0, CFStringGetLength(String)), kCFStringEncodingUTF16, 0, true, NULL, 0, &lengthRequired);
return lengthRequired+2;
}
else
return 2;
}
//---------------------------------------------------------------------------
int StringField::Compare(Field *Entry)
{
if (!Entry) return -1;
if (Entry->GetType() != GetType()) return 0;
CFStringRef compareString = ((StringField*)Entry)->GetString();
if (!String && !compareString) return 0;
if (!String && compareString) return 1;
if (!compareString) return -1;
return CFStringCompare(String, compareString, kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareDiacriticInsensitive);
}
//---------------------------------------------------------------------------
int StringField::Starts(Field *Entry)
{
if (!Entry) return -1;
if (Entry->GetType() != GetType()) return 0;
CFStringRef compareString = ((StringField*)Entry)->GetString();
if (!String || !compareString) return 0;
CFRange findRange = CFStringFind(String, compareString, kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareAnchored|kCFCompareDiacriticInsensitive);
if (findRange.location == kCFNotFound)
return 0;
return findRange.location == 0;
}
//---------------------------------------------------------------------------
int StringField::Contains(Field *Entry)
{
if (!Entry) return -1;
if (Entry->GetType() != GetType()) return 0;
CFStringRef compareString = ((StringField*)Entry)->GetString();
if (!String || !compareString) return 0;
CFRange findRange = CFStringFind(String, compareString, kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareDiacriticInsensitive);
return findRange.location != kCFNotFound;
}
Field *StringField::Clone(Table *pTable)
{
StringField *clone = new StringField(String);
clone->Pos = FIELD_CLONE;
clone->ID = ID;
clone->MaxSizeOnDisk = GetDataSize();
return clone;
}
//---------------------------------------------------------------------------
bool StringField::ApplyFilter(Field *Data, int op)
{
if (op == FILTER_ISEMPTY || op == FILTER_ISNOTEMPTY)
{
bool r = (op == FILTER_ISEMPTY);
if (!String)
return r;
if (CFStringGetLength(String) == 0)
return r;
return !r;
}
//
bool r;
StringField *compField = (StringField *)Data;
switch (op)
{
case FILTER_EQUALS:
r = !Compare(Data);
break;
case FILTER_NOTEQUALS:
r = !!Compare(Data);
break;
case FILTER_CONTAINS:
r = !!Contains(Data);
break;
case FILTER_NOTCONTAINS:
r = !Contains(Data);
break;
case FILTER_ABOVE:
r = (bool)(Compare(Data) > 0);
break;
case FILTER_ABOVEOREQUAL:
r = (bool)(Compare(compField) >= 0);
break;
case FILTER_BELOW:
r = (bool)(Compare(compField) < 0);
break;
case FILTER_BELOWOREQUAL:
r = (bool)(Compare(compField) <= 0);
break;
case FILTER_BEGINS:
r = !!Starts(compField);
break;
case FILTER_ENDS:
{
CFStringRef compareString = ((StringField*)Data)->GetString();
if (!String || !compareString) return 0;
CFRange findRange = CFStringFind(String, compareString, kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareAnchored|kCFCompareBackwards);
if (findRange.location == kCFNotFound)
r=0;
else
r = findRange.location != 0;
}
break;
case FILTER_LIKE:
/* TODO
if (compField->optimized_the)
p = compField->optimized_the;
else
{
SKIP_THE_AND_WHITESPACEW(p);
compField->optimized_the = p;
}
if (optimized_the)
d = optimized_the;
else
{
SKIP_THE_AND_WHITESPACEW(d);
optimized_the=d;
}
r = (bool)(nde_wcsicmp(d, p) == 0);
*/
r = !!Compare(compField);
break;
case FILTER_BEGINSLIKE:
/*
if (compField->optimized_the)
p = compField->optimized_the;
else
{
SKIP_THE_AND_WHITESPACEW(p);
compField->optimized_the = p;
}
if (optimized_the)
d = optimized_the;
else
{
SKIP_THE_AND_WHITESPACEW(d);
optimized_the=d;
}
r = (bool)(nde_wcsnicmp(d, p, wcslen(p)) == 0);
*/
r = !!Starts(compField);
break;
default:
r = true;
break;
}
return r;
}

50
Src/nde/osx/StringField.h Normal file
View file

@ -0,0 +1,50 @@
/*
---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
---------------------------------------------------------------------------
*/
/*
---------------------------------------------------------------------------
StringField Class Prototypes
---------------------------------------------------------------------------
*/
#ifndef __STRINGFIELD_H
#define __STRINGFIELD_H
#include <CoreFoundation/CFString.h>
class StringField : public Field
{
public:
StringField();
~StringField();
StringField(CFStringRef Str);
CFStringRef GetString(); // CFRetain this if you need to keep it for a while
void SetNDEString(CFStringRef str);
protected:
virtual void ReadTypedData(const uint8_t *, size_t len);
virtual void WriteTypedData(uint8_t *, size_t len);
virtual size_t GetDataSize(void);
virtual int Compare(Field *Entry);
virtual int Starts(Field *Entry);
virtual int Contains(Field *Entry);
virtual bool ApplyFilter(Field *Data, int op);
virtual Field *Clone(Table *pTable);
void InitField(void);
CFStringRef String;
};
#endif

659
Src/nde/osx/Table.cpp Normal file
View file

@ -0,0 +1,659 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
Table Class
Apple Mac OS X implementation
--------------------------------------------------------------------------- */
#include "../nde.h"
#include <stdio.h>
#include <string.h>
#include "../CRC.H"
const char *tSign="NDETABLE";
//---------------------------------------------------------------------------
Table::Table(const char *TableName, const char *Idx, BOOL Create, Database *_db, BOOL _Cached)
: columns_cached(false), use_row_cache(false), Scanner(this)
{
Handle = 0;
memset(column_ids, FIELD_UNKNOWN, 255);
Cached = _Cached;
db = _db;
AutoCreate = Create;
Name = strdup(TableName);
IdxName = strdup(Idx);
Init();
}
//---------------------------------------------------------------------------
void Table::Init()
{
numErrors = 0;
Scanners = new LinkedList();
// benski> cut: Handle=NULL;
IdxHandle=NULL;
FieldsRecord=NULL;
IndexList=NULL;
GLocateUpToDate = FALSE;
}
//---------------------------------------------------------------------------
Table::~Table()
{
Reset();
if (Handle) // Reset doesn't completely destroy Handle
Vfdestroy(Handle);
Handle = 0;
free(Name);
free(IdxName);
}
//---------------------------------------------------------------------------
void Table::Reset()
{
if (IndexList) IndexList->Release();
IndexList=0;
if (FieldsRecord) FieldsRecord->Release();
FieldsRecord=0;
delete Scanners;
Scanners=0;
if (Handle)
Vfclose(Handle); // close (but don't destroy) to keep mutex open.
if (IdxHandle)
Vfdestroy(IdxHandle);
IdxHandle = 0;
for (RowCache::iterator itr=rowCache.begin();itr!=rowCache.end();itr++)
{
if (itr->second)
itr->second->Release();
}
rowCache.clear();
memset(column_ids, FIELD_UNKNOWN, 255);
columns_cached=false;
}
struct IndexNewWalkerContext
{
IndexNewWalkerContext(Table *_table)
{
N = -1;
table = _table;
}
int N;
Table *table;
};
bool Table::IndexNewWalker(IndexRecord *record, Field *entry, void *context_in)
{
IndexNewWalkerContext *context = (IndexNewWalkerContext *)context_in;
IndexField *p = (IndexField *)entry;
p->index = new Index(context->table->IdxHandle, p->ID, context->N++, p->Type, FALSE, 0, context->table);
return true;
}
//---------------------------------------------------------------------------
BOOL Table::Open(void)
{
BOOL Valid;
int justcreated = 0;
if (!Handle)
Handle = Vfnew(Name, "r+b", Cached);
if (!Handle) return FALSE;
if (!Vflock(Handle))
{
Vfdestroy(Handle);
Handle = 0;
return FALSE;
}
Handle = Vfopen(Handle, Name, "r+b", Cached);
IdxHandle = Vfopen(0, IdxName, "r+b", TRUE);
Valid = (Handle && IdxHandle);
// unlock
if (Valid || !AutoCreate)
{
//if (Handle)
//Vfunlock(Handle);
}
else
{
if (Handle)
{
Vfclose(Handle);
if (IdxHandle)
Vfdestroy(IdxHandle);
IdxHandle = 0;
}
else
{
if (IdxHandle)
Vfdestroy(IdxHandle);
IdxHandle = 0;
Handle = Vfnew(Name, "w+b", Cached);
if (!Vflock(Handle))
{
Vfdestroy(Handle);
return FALSE;
}
}
Handle = Vfopen(Handle, Name, "w+b", Cached);
IdxHandle = Vfopen(0, IdxName, "w+b", TRUE);
Valid = (Handle && IdxHandle);
if (Valid)
{
Vfwrite(__TABLE_SIGNATURE__, strlen(__TABLE_SIGNATURE__), Handle);
Vfwrite(__INDEX_SIGNATURE__, strlen(__TABLE_SIGNATURE__), IdxHandle);
// TODO bensk> change if NUM_SPECIAL_RECORDS ever increases
int v=NUM_SPECIAL_RECORDS;//strlen(__TABLE_SIGNATURE__);
Vfwrite(&v, sizeof(v), IdxHandle);
// v = 0; fwrite(&v, sizeof(v), 1, IdxHandle);
v = -1; Vfwrite(&v, sizeof(v), IdxHandle); // write ID
v = 0;
for (int i=0;i<NUM_SPECIAL_RECORDS;i++)
{
Vfwrite(&v, sizeof(v), IdxHandle);
Vfwrite(&v, sizeof(v), IdxHandle);
}
Sync();
justcreated = 1;
}
}
if (!Valid)
{
if (Handle) Vfdestroy(Handle);
if (IdxHandle) Vfdestroy(IdxHandle);
Handle = NULL;
IdxHandle = NULL;
}
else
{
int Ptr;
char test1[9]={0,};
char test2[9]={0,};
Vfseek(Handle, 0, SEEK_SET);
Vfread(test1, strlen(__TABLE_SIGNATURE__), Handle);
Vfseek(IdxHandle, 0, SEEK_SET);
Vfread(test2, strlen(__INDEX_SIGNATURE__), IdxHandle);
test1[8]=0;
test2[8]=0;
if (strcmp(test1, __TABLE_SIGNATURE__) || strcmp(test2, __INDEX_SIGNATURE__))
{
if (Handle) Vfdestroy(Handle);
Handle = 0;
if (IdxHandle) Vfdestroy(IdxHandle);
IdxHandle = 0;
return FALSE;
}
// Load default index
IndexField *field;
field = new IndexField(PRIMARY_INDEX, -1, -1, CFSTR("None"));
field->index = new Index(IdxHandle, PRIMARY_INDEX, -1, -1, FALSE, 0, this);
// Get indexes
Ptr = field->index->Get(INDEX_RECORD_NUM);
IndexList = new IndexRecord(Ptr, INDEX_RECORD_NUM, Handle, this);
if (!IndexList)
{
delete field;
if (Handle) Vfdestroy(Handle);
Handle = 0;
if (IdxHandle) Vfdestroy(IdxHandle);
IdxHandle = 0;
return FALSE;
}
// Init them
IndexNewWalkerContext newContext(this);
IndexList->WalkFields(IndexNewWalker, &newContext);
// Add default in case its not there (if it is it won't be added by addfield)
IndexList->AddField(field);
// Get the default index (whether loaded or preloaded)
Scanner::index = ((IndexField*)IndexList->GetField(PRIMARY_INDEX))->index;
// If it's different from preloaded, delete preloaded
if (field->index != Scanner::index)
{
delete field;
field=0;
}
// Set up colaboration
IndexList->BuildCollaboration();
// Get columns
Ptr = Scanner::index->Get(FIELDS_RECORD_NUM);
FieldsRecord = new Record(Ptr, FIELDS_RECORD_NUM, Handle, this);
if (!FieldsRecord)
{
IndexList->Release();
IndexList=0;
if (Handle) Vfdestroy(Handle);
Handle = 0;
if (IdxHandle) Vfdestroy(IdxHandle);
IdxHandle = 0;
return FALSE;
}
// update the column cache
FieldsRecord->WalkFields(BuildColumnCache, this);
columns_cached=true;
}
#if 0 // TODO
if (Valid && !justcreated)
{
if (IndexList->NeedFix())
Compact();
}
#endif
if (Valid) First();
if (Handle)
Vfunlock(Handle);
return Valid;
}
//---------------------------------------------------------------------------
void Table::Close(void)
{
int v=0;
if (Handle && IndexList && Vflock(Handle, 0))
{
IndexList->WalkFields(IndexWriteWalker, 0);
}
delete Scanners;
Scanners = NULL;
Vsync(Handle);
if (IdxHandle)
{
Vfdestroy(IdxHandle);
IdxHandle = NULL;
v |= 2;
}
if (Handle)
{
Vfdestroy(Handle);
Handle = NULL;
v |= 1;
}
if (v != 3)
return;
}
bool Table::IndexWriteWalker(IndexRecord *record, Field *entry, void *context)
{
IndexField *field = (IndexField *)entry;
field->index->WriteIndex();
return true;
}
//---------------------------------------------------------------------------
void Table::Sync(void)
{
if (!Vflock(Handle))
return;
if (IndexList)
IndexList->WalkFields(IndexWriteWalker, 0);
int err=0;
if (!err && Handle) err|=Vsync(Handle);
if (!err && IdxHandle) err|=Vsync(IdxHandle);
Vfunlock(Handle);
}
//---------------------------------------------------------------------------
ColumnField *Table::NewColumn(unsigned char FieldID, CFStringRef FieldName, unsigned char FieldType, BOOL indexUnique)
{
columns_cached=false; // if they start writing new columns, kill the columns cache until they PostColumns()
ColumnField *f = GetColumnById(FieldID);
if (f) {
int t = f->GetDataType();
if (t != FieldType) {
if (CompatibleFields(t, FieldType))
{
f->SetDataType(FieldType);
goto aok;
}
}
return NULL;
}
aok:
if (GetColumnByName(FieldName))
return NULL;
ColumnField *field = new ColumnField(FieldID, FieldName, FieldType, this);
column_ids[FieldID]=FieldType;
FieldsRecord->AddField(field);
return field;
}
void Table::SetFieldSearchableById(unsigned char field_id, bool searchable)
{
ColumnField *column = GetColumnById(field_id);
if (column)
column->SetSearchable(searchable);
if (searchable)
{
search_fields.insert(field_id);
}
else
{
search_fields.erase(field_id);
}
}
//---------------------------------------------------------------------------
bool Table::BuildColumnCache(Record *record, Field *entry, void *context)
{
Table *table = (Table *)context;
ColumnField *column = (ColumnField *)entry;
unsigned char field_id=column->GetFieldId();
table->column_ids[field_id] = column->GetDataType();
if (column->IsSearchableField())
{
table->search_fields.insert(field_id);
}
else
{
table->search_fields.erase(field_id);
}
return true;
}
//---------------------------------------------------------------------------
void Table::PostColumns(void)
{
FieldsRecord->WriteFields(this, FIELDS_RECORD_NUM);
memset(column_ids, FIELD_UNKNOWN, 255);
FieldsRecord->WalkFields(BuildColumnCache, this);
columns_cached=true;
}
unsigned char Table::GetColumnType(unsigned char Id)
{
if (columns_cached)
{
return column_ids[Id];
}
else
{
return GetColumnById(Id)->GetDataType();
}
}
//---------------------------------------------------------------------------
IndexField *Table::GetIndexByName(CFStringRef name)
{
if (!IndexList)
return NULL;
return IndexList->GetIndexByName(name);
}
//---------------------------------------------------------------------------
IndexField *Table::GetIndexById(unsigned char Id)
{
if (!IndexList)
return NULL;
return (IndexField *)IndexList->GetField(Id);
}
//---------------------------------------------------------------------------
void Table::AddIndexByName(CFStringRef name, CFStringRef desc)
{
ColumnField *header = GetColumnByName(name);
if (header)
{
unsigned char Idx = header->ID;
AddIndexById(Idx, desc);
}
}
//---------------------------------------------------------------------------
void Table::AddIndexById(unsigned char Id, CFStringRef desc)
{
if (GetIndexById(Id)) return;
ColumnField *col = GetColumnById(Id);
if (!col)
return;
IndexField *newindex = new IndexField(Id, IndexList->GetColumnCount(), col->GetDataType(), desc);
newindex->index = new Index(IdxHandle, Id, IndexList->GetColumnCount(), col->GetDataType(), TRUE, Scanner::index->NEntries, this);
IndexList->AddField(newindex);
IndexField *previous = (IndexField *)newindex->prev;
previous->index->Colaborate(newindex);
IndexField *primary_index = (IndexField *)IndexList->GetField(PRIMARY_INDEX);
newindex->index->Colaborate(primary_index);
previous->index->Propagate();
IndexList->WriteFields(this);
}
//---------------------------------------------------------------------------
BOOL Table::CheckIndexing(void)
{
if (IndexList->GetColumnCount() == 0) return TRUE;
for (int i=0;i<Scanner::index->NEntries;i++)
{
if (!IndexList->CheckIndexing(i))
return FALSE;
}
return TRUE;
}
struct IndexWalkerThunkContext
{
void *context;
Table *_this;
Table::IndexWalker callback;
};
bool Table::IndexWalkerThunk(IndexRecord *record, Field *entry, void *context_in)
{
IndexWalkerThunkContext *context = (IndexWalkerThunkContext *)context_in;
return context->callback(context->_this, (IndexField *)entry, context->context);
}
//---------------------------------------------------------------------------
void Table::WalkIndices(IndexWalker callback, void *context)
{
if (IndexList && callback)
{
IndexWalkerThunkContext walkerContext = { context, this, callback };
IndexList->WalkFields(IndexWalkerThunk, &walkerContext);
}
}
//---------------------------------------------------------------------------
void Table::DropIndex(IndexField *Ptr)
{
if (!Ptr || Ptr->Type != FIELD_INDEX) return;
if (Scanner::index == Ptr->index)
{
Scanner::index = ((IndexField*)IndexList->GetField(PRIMARY_INDEX))->index;
IndexList->BuildCollaboration();
}
IndexList->RemoveField(Ptr);
if (Scanner::index->SecIndex == Ptr)
Scanner::index->SecIndex = 0;
IndexList->SetModified(TRUE);
IndexList->WriteFields(this);
}
//---------------------------------------------------------------------------
void Table::DropIndexByName(CFStringRef desc)
{
IndexField *indx = GetIndexByName(desc);
if (CFStringCompare(desc, CFSTR("None"), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
return;
if (indx)
DropIndex(indx);
}
//---------------------------------------------------------------------------
void Table::DropIndexById(unsigned char Id)
{
if (!IndexList)
return;
if (Id == (unsigned char)PRIMARY_INDEX) return;
IndexField *indx=(IndexField *)IndexList->GetField(Id);
if (indx)
DropIndex(indx);
}
//---------------------------------------------------------------------------
BOOL Table::LocateByIdEx(int Id, int From, Field *field, int comp_mode)
{
return Scanner::LocateByIdEx(Id, From, field, NULL, comp_mode);
}
//---------------------------------------------------------------------------
Record *Table::GetColumns(void)
{
if (!FieldsRecord)
return NULL;
return FieldsRecord;
}
//---------------------------------------------------------------------------
Scanner *Table::NewScanner()
{
Scanner *s = new Scanner(this);
/*if (Scanners->GetNElements() > 0)*/
s->index = Scanner::index;
Scanners->AddEntry(s, TRUE);
return s;
}
//---------------------------------------------------------------------------
Scanner *Table::GetDefaultScanner(void)
{
return this;
}
//---------------------------------------------------------------------------
void Table::DeleteScanner(Scanner *scan)
{
if (!scan) return;
Scanners->RemoveEntry(scan);
}
//---------------------------------------------------------------------------
void Table::IndexModified(void)
{
Scanner *s = (Scanner *)Scanners->GetHead();
while (s)
{
s->IndexModified();
s = (Scanner *)s->GetNext();
}
}
//---------------------------------------------------------------------------
void Table::SetGlobalLocateUpToDate(BOOL is) {
GLocateUpToDate = is;
}
ColumnField *Table::GetColumnById(unsigned char Idx)
{
if (!FieldsRecord)
return NULL;
return (ColumnField *)FieldsRecord->GetField(Idx);
}
ColumnField *Table::GetColumnByName(CFStringRef FieldName)
{
return FieldsRecord->GetColumnByName(FieldName);
}
void Table::RowCache_Delete(int position)
{
if (use_row_cache)
{
RowCache::iterator found = rowCache.find(position);
if (found != rowCache.end())
{
if (found->second)
found->second->Release();
rowCache.erase(found);
}
}
}
void Table::RowCache_Remove(int position)
{
if (use_row_cache)
{
Record *&row = rowCache[position];
if (row)
{
row->Release();
}
row = 0;
}
}
void Table::RowCache_Add(Record *record, int position)
{
if (use_row_cache)
{
record->Retain();
Record *&row = rowCache[position];
if (row)
{
row->Release();
}
row = record;
}
}
Record *Table::RowCache_Get(int position)
{
if (!use_row_cache)
return 0;
Record *row = rowCache[position];
if (row)
row->Retain();
return row;
}
void Table::EnableRowCache()
{
use_row_cache=true;
}

165
Src/nde/osx/Table.h Normal file
View file

@ -0,0 +1,165 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
Table Class Prototypes
Apple Mac OS X implementation
--------------------------------------------------------------------------- */
#ifndef __TABLE_H
#define __TABLE_H
#include <stdio.h>
#include "Scanner.h"
#include <map>
#include "IndexRecord.h"
class Table : private Scanner
{
public:
// TODO: move these back to protected
VFILE *Handle;
using Scanner::index;
bool use_row_cache;
BOOL GLocateUpToDate;
private:
void Init();
void Reset();
private:
LinkedList *Scanners;
protected:
char *Name; // TODO: CFStringRef
char *IdxName; // TODO: CFStringRef
VFILE *IdxHandle;
BOOL AutoCreate;
Record *FieldsRecord;
IndexRecord *IndexList;
Database *db;
BOOL Cached;
int numErrors;
using Scanner::Edition;
bool columns_cached;
unsigned char column_ids[256];
typedef std::map<int, Record*> RowCache;
RowCache rowCache;
// Tables
static bool Compact_ColumnWalk(Record *record, Field *entry, void *context_in);
static bool Compact_ColumnWalk2(Record *record, Field *entry, void *context_in);
static bool Compact_IndexWalk(Table *table, IndexField *entry, void *context);
static bool IndexWriteWalker(IndexRecord *record, Field *entry, void *context);
static bool IndexWalkerThunk(IndexRecord *record, Field *entry, void *context);
static bool IndexNewWalker(IndexRecord *record, Field *entry, void *context);
static bool BuildColumnCache(Record *record, Field *entry, void *context);
public:
typedef bool (*IndexWalker)(Table *table, IndexField *entry, void *context);
Table(const char *TableName, const char *IdxName, BOOL Create, Database *db, BOOL Cached);
~Table();
BOOL Open(void);
void Close(void);
// Columns
ColumnField *NewColumn(unsigned char Id, CFStringRef name, unsigned char type, BOOL indexUniques);
void DeleteColumn(ColumnField *field); // todo
void DeleteColumnByName(const wchar_t *name); // todo
void DeleteColumnById(unsigned char Id); // todo
void PostColumns(void);
NDE_API Record *GetColumns(void);
ColumnField *GetColumnByName(CFStringRef FieldName);
ColumnField *GetColumnById(unsigned char Idx);
unsigned char GetColumnType(unsigned char Id);
// Fields
using Scanner::NewFieldByName;
using Scanner::NewFieldById;
using Scanner::GetFieldByName;
using Scanner::GetFieldById;
using Scanner::DeleteField;
using Scanner::DeleteFieldByName;
using Scanner::DeleteFieldById;
// Records
using Scanner::First;
using Scanner::Last;
using Scanner::Next;
using Scanner::Previous;
using Scanner::Eof;
using Scanner::Bof;
using Scanner::New;
using Scanner::Insert;
using Scanner::Edit;
using Scanner::Cancel;
using Scanner::Post;
using Scanner::Delete;
using Scanner::GetRecordsCount;
using Scanner::GetRecordById;
using Scanner::GetRecordId;
void Sync(void);
using Scanner::LocateByName;
using Scanner::LocateById;
BOOL LocateByIdEx(int Id, int From, Field *field, int comp_mode);
// Indexes
void AddIndexByName(CFStringRef FieldName, CFStringRef KeyName);
void AddIndexById(unsigned char Id, CFStringRef KeyName);
void WalkIndices(IndexWalker callback, void *context);
IndexField *GetIndexByName(CFStringRef name);
IndexField *GetIndexById(unsigned char Id);
using Scanner::SetWorkingIndexByName;
using Scanner::SetWorkingIndexById;
NDE_API BOOL CheckIndexing(void);
void DropIndexByName(CFStringRef desc);
void DropIndexById(unsigned char Id);
void DropIndex(IndexField *Ptr);
void IndexModified(void);
// Filters
using Scanner::AddFilterByName;
using Scanner::AddFilterById;
using Scanner::AddFilterOp;
using Scanner::RemoveFilters;
// Scanners
Scanner *NewScanner();
Scanner *GetDefaultScanner(void);
void DeleteScanner(Scanner *scan);
// Misc
using Scanner::FragmentationLevel;
void Compact(int *progress = NULL);
void SetGlobalLocateUpToDate(BOOL is);
// Row Cache
void RowCache_Delete(int position);
void RowCache_Remove(int position);
void RowCache_Add(Record *record, int position);
Record *RowCache_Get(int position);
NDE_API void EnableRowCache();
// Searching
void SetFieldSearchableById(unsigned char field_id, bool searchable);
int HasErrors()
{
return numErrors > 0;
}
int NumErrors()
{
return numErrors;
}
void IncErrorCount()
{
numErrors++;
}
};
#endif

542
Src/nde/osx/Vfs.cpp Normal file
View file

@ -0,0 +1,542 @@
/* ---------------------------------------------------------------------------
Nullsoft Database Engine
--------------------
codename: Near Death Experience
--------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
Virtual File System
--------------------------------------------------------------------------- */
#include "nde.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "Vfs.h"
#ifndef EOF
#define EOF -1
#endif
#include "../nu/strsafe.h"
/* the FILE (fopen/fwrite/etc) implementation for Mac and Linux */
VFILE *Vfnew(const char *fl, const char *mode, BOOL Cached)
{
if (!fl) return NULL;
VFILE *f = (VFILE *)malloc(sizeof(VFILE));
if (!f)
return NULL;
memset(f, 0, sizeof(VFILE));
#ifdef NDE_ALLOW_NONCACHED
f->cached = Cached;
#else
f->cached = TRUE;
#endif
if (!strchr(mode, '+'))
{
if (strchr(mode, 'r'))
f->mode = VFS_READ | VFS_MUSTEXIST;
if (strchr(mode, 'w'))
f->mode = VFS_WRITE | VFS_CREATE | VFS_NEWCONTENT;
if (strchr(mode, 'a'))
f->mode = VFS_WRITE | VFS_CREATE | VFS_SEEKEOF;
}
else
{
if (strstr(mode, "r+"))
f->mode = VFS_WRITE | VFS_MUSTEXIST;
if (strstr(mode, "w+"))
f->mode = VFS_WRITE | VFS_CREATE | VFS_NEWCONTENT;
if (strstr(mode, "a+"))
f->mode = VFS_WRITE | VFS_CREATE | VFS_SEEKEOF;
}
if (f->mode == 0 || ((f->mode & VFS_READ) && (f->mode & VFS_WRITE)))
{
free(f);
return NULL;
}
snprintf(f->lockname, sizeof(f->lockname), "%s.lock", fl);
return f;
}
//----------------------------------------------------------------------------
VFILE *Vfopen(VFILE *f, const char *fl, const char *mode, BOOL Cached)
{
if (!f)
{
f = Vfnew(fl, mode, Cached);
if (!f)
return 0;
}
if (!f && !fl) return NULL;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
f->rfile = fopen(fl, mode);
if (f->rfile)
f->filename = _strdup(fl);
}
else
{
free(f);
return NULL;
}
return f;
}
#endif
if (f->mode & VFS_MUSTEXIST)
{
if (access(fl, 0) != 0)
{
free(f);
return NULL;
}
}
if (!(f->mode & VFS_NEWCONTENT))
{
FILE *pf;
pf = fopen(fl, "rb");
if (!pf)
{
f->data = (unsigned char *)calloc(VFILE_INC, 1);
if (f->data == NULL)
{
free(f);
return NULL;
}
f->filesize = 0;
f->maxsize = VFILE_INC;
}
else
{
fseek(pf, 0, SEEK_END);
f->filesize = ftell(pf);
fseek(pf, 0, SEEK_SET);
f->data = (unsigned char *)calloc(f->filesize, 1);
if (f->data == NULL)
{
free(f);
return NULL;
}
f->maxsize = f->filesize;
fread(f->data, f->filesize, 1, pf);
fclose(pf);
}
}
if (f->mode & VFS_SEEKEOF)
f->ptr = f->filesize;
f->filename = strdup(fl);
return f;
}
//----------------------------------------------------------------------------
void Vfclose(VFILE *f)
{
if (!f) return;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
free(f->filename);
if (f->rfile)
fclose(f->rfile);
f->rfile=0;
// free(f);
return;
}
#endif
if (!(f->mode & VFS_WRITE))
{
free(f->filename);
free(f->data);
//free(f);
return;
}
Vsync(f);
while (f->locks)
Vfunlock(f, 1);
free(f->filename);
free(f->data);
//free(f);
}
//----------------------------------------------------------------------------
size_t Vfread(void *ptr, size_t size, VFILE *f)
{
if (!ptr || !f) return 0;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
return fread(ptr, 1, size, f->rfile);
}
#endif
size_t s = size;
if (!s) return 0;
if (s + f->ptr > f->filesize)
{
//FUCKO: remove this
if (!(f->ptr < f->filesize))
{
// if (!f->flushtable) // this would be ideal, if we could figure out f->flushtable
// f->flushtable=MessageBox(g_hwnd,"DB read failed, DB may be corrupted.\r\n\r\n"
// "Hit Retry to continue, or Cancel to clear the DB and start over","Winamp Library Error",MB_RETRYCANCEL) == IDCANCEL; //fucko
//MessageBox(g_hwnd,"DB read failed, DB may be corrupted. If this error persists, remove all files from the library.",
// "Winamp Library Error",MB_OK);
return 0;
}
s = f->filesize - f->ptr;
}
memcpy(ptr, f->data+f->ptr, s);
f->ptr += s;
return (s/size);
}
//----------------------------------------------------------------------------
void Vfwrite(const void *ptr, size_t size, VFILE *f)
{
if (!ptr || !f) return;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
fwrite(ptr, size*n, f->rfile);
return;
}
#endif
f->dirty=1;
if (size + f->ptr > f->maxsize)
{
// grow f->data,f->maxsize to be (size + f->ptr + VFILE_INC-1)&~(VFILE_INC-1)
// instead of calling Vgrow again which gets kinda slow
size_t newsize=(size + f->ptr + VFILE_INC-1)&~(VFILE_INC-1);
f->data=(unsigned char *)realloc(f->data,newsize);
if (f->data == NULL) return;
memset(f->data+f->maxsize,0,newsize-f->maxsize);
f->maxsize=newsize;
}
memcpy(f->data + f->ptr, ptr, size);
f->ptr += size;
if (f->ptr > f->filesize)
f->filesize = f->ptr;
}
//----------------------------------------------------------------------------
void Vgrow(VFILE *f)
{
if (!f) return;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached) return;
#endif
f->data = (unsigned char *)realloc(f->data, f->maxsize + VFILE_INC);
f->maxsize += VFILE_INC;
}
//----------------------------------------------------------------------------
void Vfputs(char *str, VFILE *f)
{
if (!f) return;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
fputs(str, f->rfile);
return;
}
#endif
Vfwrite(str, strlen(str), f);
}
//----------------------------------------------------------------------------
void Vfputc(char c, VFILE *f)
{
if (!f) return;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
fputc(c, f->rfile);
return;
}
#endif
Vfwrite(&c, 1, f);
}
/* benski> unused:
// not mac compliant
//----------------------------------------------------------------------------
char *Vfgets(char *dest, int n, VFILE *f) {
if (!f) return NULL;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
#ifdef NDE_NOWIN32FILEIO
return fgets(dest, n, f->rfile);
#else
#error port me!
#endif
}
#endif
unsigned char c=0;
char *p;
int l=0;
p = dest;
while (l < n && !Vfeof(f)) {
c = f->data[f->ptr];
f->ptr++;
*p = c;
p++;
l++;
if (c == '\n') {
if (!Vfeof(f) && f->data[f->ptr] == '\r') {
f->ptr++;
}
break;
}
}
*p=0;
return dest;
}
*/
/* benski> unused:
//----------------------------------------------------------------------------
char Vfgetc(VFILE *f) {
if (!f) return EOF;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
#ifdef NDE_NOWIN32FILEIO
return fgetc(f->rfile);
#else
#error port me#
#endif
#endif
if (!Vfeof(f))
return f->data[f->ptr++];
return EOF;
}
*/
//----------------------------------------------------------------------------
unsigned long Vftell(VFILE *f)
{
if (!f) return (unsigned)-1;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
return ftell(f->rfile);
}
#endif
return f->ptr;
}
//----------------------------------------------------------------------------
void Vfseek(VFILE *f, long i, int whence)
{
if (!f) return;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
fseek(f->rfile, i, whence);
return;
}
#endif
switch (whence)
{
case SEEK_SET:
f->ptr = i;
break;
case SEEK_CUR:
f->ptr += i;
break;
case SEEK_END:
f->ptr = f->filesize+i;
break;
}
}
//----------------------------------------------------------------------------
int Vfeof(VFILE *f)
{
if (!f) return -1;
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
return feof(f->rfile);
}
#endif
return (f->ptr >= f->filesize);
}
//----------------------------------------------------------------------------
int Vsync(VFILE *f)
{
if (!f) return 0;
if (!f->dirty) return 0;
if (f->mode & VFS_WRITE)
{
#ifdef NDE_ALLOW_NONCACHED
if (!f->cached)
{
int p=ftell(f->rfile);
fclose(f->rfile);
f->rfile = fopen(f->filename, "r+b");
if (!f->rfile)
return 1;
fseek(f->rfile, p, SEEK_SET);
return 0;
}
#endif
char newfn[1024], oldfn[1024];
DWORD mypid=getpid();
snprintf(newfn,sizeof(newfn), "%s.n3w%08X",f->filename,mypid);
snprintf(oldfn,sizeof(oldfn), "%s.o1d%08X",f->filename,mypid);
unlink(newfn);
unlink(oldfn);
tryagain:
FILE *pf = fopen(newfn, "wb");
if (!pf || fwrite(f->data, f->filesize, 1, pf) != 1)
{
if (pf) fclose(pf);
printf("Error flushing DB to disk (is your drive full?)\n\nHit (R)etry to try again (recommended), or (C)ancel to abort (NOT recommended, and may leave the DB in an unuseable state)");
fflush(stdout);
char c;
while (1)
{
scanf("%c", &c);
// clear_stdin();
c = toupper(c);
if (c == 'R') goto tryagain;
else if (c == 'C') break;
}
unlink(newfn);
return 1;
}
fclose(pf);
rename(f->filename,oldfn); // save old file
int rv=0;
tryagain2:
if (rename(newfn,f->filename))
{
printf("Error updating DB file on disk. This should never really happen\n\nHit (R)etry to try again (recommended), or (C)ancel to abort (NOT recommended, and may leave the DB in an unuseable state)");
fflush(stdout);
char c;
while (1)
{
scanf("%c", &c);
// clear_stdin();
c = toupper(c);
if (c == 'R') goto tryagain2;
else if (c == 'C') break;
}
rename(oldfn,f->filename); // restore old file
rv=1;
}
// clean up our temp files
unlink(oldfn);
unlink(newfn);
//free(newfn);
//free(oldfn);
if (rv == 0)
f->dirty=0;
return rv;
}
f->dirty=0;
return 0;
}
void Vfdestroy(VFILE *f)
{
// benski> TODO:
if (f)
{
Vfclose(f);
while (f->locks)
Vfunlock(f, 1);
// TODO if (f->mutex) CloseHandle(f->mutex);
free(f);
}
}
// benski> TODO implement these with fopen
// returns 0 on failure
int Vflock(VFILE *fl, BOOL is_sync)
{
#ifndef NO_TABLE_WIN32_LOCKING
if (!fl) return 0;
if (!is_sync && fl->cached)
return 1;
if (fl->locks++ == 0)
{
int retry_cnt=0;
FILE *fFile;
do
{
fFile = fopen(fl->lockname, "wb");
if (fFile == 0) Sleep(100);
}
while (fFile == 0 && retry_cnt++ < 100); // try for 10 seconds
if (fFile == INVALID_HANDLE_VALUE) return 0; // db already locked, fail gracefully
fl->lockFile = fFile;
}
#endif
return 1;
}
void Vfunlock(VFILE *fl, BOOL is_sync)
{
#ifndef NO_TABLE_WIN32_LOCKING
if (!is_sync && fl->cached)
return;
if (--fl->locks == 0)
{
if (fl && fl->lockFile && fl->lockFile != INVALID_HANDLE_VALUE)
{
fclose(fl->lockFile);
unlink(fl->lockname);
}
}
#endif
}

66
Src/nde/osx/Vfs.h Normal file
View file

@ -0,0 +1,66 @@
#ifndef __NDE_VFS_H
#define __NDE_VFS_H
#include <bfc/platform/types.h>
#include <stdio.h>
//#define NDE_ALLOW_NONCACHED
/*
#ifdef NDE_ALLOW_NONCACHED
#ifndef NDE_NOWIN32FILEIO
#error NDE_ALLOW_NONCACHED at least for now requires NDE_NOWIN32FILEIO
#endif
#endif
*/
#define VFILE_INC 65536
#define VFS_READ 1
#define VFS_WRITE 2
#define VFS_SEEKEOF 4
#define VFS_CREATE 8
#define VFS_NEWCONTENT 16
#define VFS_MUSTEXIST 32
typedef struct {
uint8_t *data;
unsigned long ptr;
unsigned long filesize;
unsigned long maxsize;
char *filename;
char mode;
BOOL cached;
int dirty;
#ifdef NDE_ALLOW_NONCACHED
FILE *rfile;
#endif
FILE *lockFile;
char lockname[1024];
int locks;
} VFILE;
#ifdef __cplusplus
extern "C" {
#endif
VFILE *Vfnew(const char *fl, const char *mode, BOOL Cached);
VFILE *Vfopen(VFILE *f, const char *fl, const char *mode, BOOL Cached);
size_t Vfread(void *ptr, size_t size, VFILE *buf);
void Vfseek(VFILE *fl, long i, int whence);
unsigned long Vftell(VFILE *fl);
void Vfclose(VFILE *fl);
void Vfdestroy(VFILE *fl); // benski> TODO:
void Vfwrite(const void *ptr, size_t size, VFILE *f);
int Vfeof(VFILE *fl);
int Vsync(VFILE *fl); // 1 on error updating
int Vflock(VFILE *fl, BOOL is_sync=TRUE); // returns 0 on failure
void Vfunlock(VFILE *fl, BOOL is_sync=TRUE);
#ifdef __cplusplus
}
#endif
#endif

640
Src/nde/osx/nde_c.cpp Normal file
View file

@ -0,0 +1,640 @@
#include "nde_c.h"
#include "nde.h"
#ifdef _WIN32
#include "../nu/AutoCharFn.h"
#include "../nu/AutoWide.h"
#endif
/* Database */
#ifdef _WIN32
nde_database_t NDE_CreateDatabase(HINSTANCE hInstance)
{
return (nde_database_t)new Database(hInstance);
}
#else
nde_database_t NDE_CreateDatabase()
{
return (nde_database_t)new Database();
}
#endif
void NDE_DestroyDatabase(nde_database_t db)
{
delete (Database *)db;
}
#ifdef _WIN32
nde_table_t NDE_Database_OpenTable(nde_database_t db, const wchar_t *filename, const wchar_t *indexname, int create, int cache)
{
Database *database = (Database *)db;
if (database && filename)
return (nde_table_t)database->OpenTable(filename, indexname, (BOOL)create, (BOOL)cache);
else
return 0;
}
#else
nde_table_t NDE_Database_OpenTable(nde_database_t db, const char *filename, const char *indexname, int create, int cache)
{
Database *database = (Database *)db;
if (database && filename)
return (nde_table_t)database->OpenTable(filename, indexname, (BOOL)create, (BOOL)cache);
else
return 0;
}
#endif
void NDE_Database_CloseTable(nde_database_t db, nde_table_t t)
{
Database *database = (Database *)db;
Table *table = (Table *)t;
if (database && table)
{
database->CloseTable(table);
}
}
/* Table */
#ifdef _WIN32
nde_field_t NDE_Table_NewColumn(nde_table_t t, unsigned char id, const char *name, unsigned char type)
{
Table *table = (Table *)t;
if (table)
return (nde_field_t)table->NewColumn(id, AutoWide(name), type, FALSE);
else
return 0;
}
#else
nde_field_t NDE_Table_NewColumn(nde_table_t t, unsigned char id, CFStringRef name, unsigned char type)
{
Table *table = (Table *)t;
if (table)
return (nde_field_t)table->NewColumn(id, name, type, FALSE);
else
return 0;
}
#endif
void NDE_Table_PostColumns(nde_table_t t)
{
Table *table = (Table *)t;
if (table)
table->PostColumns();
}
#ifdef _WIN32
void NDE_Table_AddIndexByID(nde_table_t t, unsigned char id, const char *name)
{
Table *table = (Table *)t;
if (table)
table->AddIndexById(id, AutoWide(name));
}
#else
void NDE_Table_AddIndexByID(nde_table_t t, unsigned char id, CFStringRef name)
{
Table *table = (Table *)t;
if (table)
table->AddIndexById(id, name);
}
#endif
nde_scanner_t NDE_Table_CreateScanner(nde_table_t t)
{
Table *table = (Table *)t;
if (table)
return (nde_scanner_t)table->NewScanner();
else
return 0;
}
void NDE_Table_DestroyScanner(nde_table_t t, nde_scanner_t s)
{
Table *table = (Table *)t;
Scanner *scanner = (Scanner *)s;
if (table && scanner)
table->DeleteScanner(scanner);
}
void NDE_Table_Sync(nde_table_t t)
{
Table *table = (Table *)t;
if (table)
table->Sync();
}
#ifdef _WIN32
void NDE_Table_Compact(nde_table_t t, int *progress)
{
Table *table = (Table *)t;
if (table)
table->Compact(progress);
}
#endif
int NDE_Table_GetRecordsCount(nde_table_t t)
{
Table *table = (Table *)t;
if (table)
return table->GetRecordsCount();
else
return 0;
}
nde_field_t NDE_Table_GetColumnByID(nde_table_t t, unsigned char id)
{
Table *table = (Table *)t;
if (table)
return (nde_field_t)table->GetColumnById(id);
else
return 0;
}
#ifdef _WIN32
nde_field_t NDE_Table_GetColumnByName(nde_table_t t, const char *name)
{
Table *table = (Table *)t;
if (table && name)
return (nde_field_t)table->GetColumnByName(AutoWide(name));
else
return 0;
}
#else
nde_field_t NDE_Table_GetColumnByName(nde_table_t t, CFStringRef name)
{
Table *table = (Table *)t;
if (table && name)
return (nde_field_t)table->GetColumnByName(name);
else
return 0;
}
#endif
void NDE_Table_SetColumnSearchableByID(nde_table_t t, unsigned char id, int searchable)
{
Table *table = (Table *)t;
if (table)
table->SetFieldSearchableById(id, !!searchable);
}
/* Scanner */
#ifdef _WIN32
int NDE_Scanner_Query(nde_scanner_t s, const wchar_t *query)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return scanner->Query(query);
else
return 0;
}
void NDE_Scanner_Search(nde_scanner_t s, const wchar_t *search_term)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
scanner->Search(search_term);
}
const wchar_t *NDE_Scanner_GetLastQuery(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return scanner->GetLastQuery();
else
return 0;
}
#elif defined(__APPLE__)
int NDE_Scanner_Query(nde_scanner_t s, const char *query)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return scanner->Query(query);
else
return 0;
}
CFStringRef NDE_Scanner_GetLastQuery(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return scanner->GetLastQuery();
else
return 0;
}
#endif
int NDE_Scanner_GetRecordsCount(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return scanner->GetRecordsCount();
else
return 0;
}
void NDE_Scanner_New(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
scanner->New();
}
void NDE_Scanner_Post(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
scanner->Post();
}
void NDE_Scanner_First(nde_scanner_t s, int *killswitch)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
scanner->First(killswitch);
}
void NDE_Scanner_Delete(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
scanner->Delete();
}
void NDE_Scanner_Edit(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
scanner->Edit();
}
int NDE_Scanner_EOF(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return scanner->Eof();
else
return 1;
}
int NDE_Scanner_BOF(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return scanner->Bof();
else
return 1;
}
nde_field_t NDE_Scanner_NewFieldByID(nde_scanner_t s, unsigned char id)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return (nde_field_t)scanner->NewFieldById(id, PERM_READWRITE);
else
return 0;
}
#ifdef _WIN32
nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t s, const char *name)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return (nde_field_t)scanner->NewFieldByName(AutoWide(name), PERM_READWRITE);
else
return 0;
}
#else
nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t s, CFStringRef name)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return (nde_field_t)scanner->NewFieldByName(name, PERM_READWRITE);
else
return 0;
}
#endif
nde_field_t NDE_Scanner_GetFieldByID(nde_scanner_t s, unsigned char id)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return (nde_field_t)scanner->GetFieldById(id);
else
return 0;
}
#ifdef _WIN32
nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t s, const char *name)
{
Scanner *scanner = (Scanner *)s;
if (scanner && name)
return (nde_field_t)scanner->GetFieldByName(AutoWide(name));
else
return 0;
}
#else
nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t s, CFStringRef name)
{
Scanner *scanner = (Scanner *)s;
if (scanner && name)
return (nde_field_t)scanner->GetFieldByName(name);
else
return 0;
}
#endif
void NDE_Scanner_AddFilterByID(nde_scanner_t s, unsigned char id, nde_field_t f, unsigned char filter_operation)
{
Scanner *scanner = (Scanner *)s;
Field *field = (Field *)f;
if (scanner && field)
scanner->AddFilterById(id, field, filter_operation);
}
int NDE_Scanner_LocateInteger(nde_scanner_t s, unsigned char id, int from, int value, int *nskip, int compare_mode)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
{
IntegerField field(value);
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
}
else
return 0;
}
#ifdef _WIN32
int NDE_Scanner_LocateString(nde_scanner_t s, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
{
StringField field(value);
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
}
else
return 0;
}
int NDE_Scanner_LocateNDEString(nde_scanner_t s, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
{
StringField field(value, STRING_IS_NDESTRING);
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
}
else
return 0;
}
#endif
#ifdef _WIN32
int NDE_Scanner_LocateFilename(nde_scanner_t s, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
{
FilenameField field(value);
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
}
else
return 0;
}
int NDE_Scanner_LocateNDEFilename(nde_scanner_t s, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
{
FilenameField field(value, STRING_IS_NDESTRING);
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
}
else
return 0;
}
#endif
int NDE_Scanner_LocateField(nde_scanner_t s, unsigned char id, int from, nde_field_t f, int *nskip, int compare_mode)
{
Scanner *scanner = (Scanner *)s;
Field *field = (Field *)f;
if (scanner && field)
{
return scanner->LocateByIdEx(id, from, field, nskip, compare_mode);
}
else
return 0;
}
void NDE_Scanner_DeleteField(nde_scanner_t s, nde_field_t f)
{
Scanner *scanner = (Scanner *)s;
Field *field = (Field *)f;
if (scanner && field)
{
scanner->DeleteField(field);
}
}
void NDE_Scanner_RemoveFilters(nde_scanner_t s)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
scanner->RemoveFilters();
}
int NDE_Scanner_Next(nde_scanner_t s, int *killswitch)
{
Scanner *scanner = (Scanner *)s;
if (scanner)
return scanner->Next(killswitch);
else
return 0;
}
/* Filter functions */
unsigned char NDE_Filter_GetID(nde_filter_t f)
{
Filter *filter = (Filter *)f;
if (filter)
return filter->GetId();
else
return FILTERS_INVALID; // right value but I'm not sure if it's the best constant name to use
}
NDE_API unsigned char NDE_Filter_GetOp(nde_filter_t f)
{
Filter *filter = (Filter *)f;
if (filter)
return filter->GetOp();
else
return FILTERS_INVALID; // right value but I'm not sure if it's the best constant name to use
}
NDE_API nde_field_t NDE_Filter_GetData(nde_filter_t f)
{
Filter *filter = (Filter *)f;
if (filter)
return (nde_field_t)filter->Data();
else
return 0;
}
/* Field functions */
unsigned char NDE_Field_GetType(nde_field_t f)
{
Field *field = (Field *)f;
if (field)
return field->GetType();
else
return FIELD_UNKNOWN;
}
unsigned char NDE_Field_GetID(nde_field_t f)
{
Field *field = (Field *)f;
if (field)
return field->GetFieldId();
else
return FIELD_UNKNOWN;
}
/* StringField functions */
#ifdef _WIN32
void NDE_StringField_SetNDEString(nde_field_t f, wchar_t *nde_string)
{
StringField *field = (StringField *)(Field *)f;
if (field)
field->SetNDEString(nde_string);
}
wchar_t *NDE_StringField_GetString(nde_field_t f)
{
StringField *field = (StringField *)(Field *)f;
if (field)
return field->GetStringW();
else
return 0;
}
#ifdef _WIN32
void NDE_StringField_SetString(nde_field_t f, const wchar_t *str)
{
StringField *field = (StringField *)(Field *)f;
if (field)
field->SetStringW(str);
}
#endif
#elif defined(__APPLE__)
void NDE_StringField_SetString(nde_field_t f, CFStringRef nde_string)
{
StringField *field = (StringField *)(Field *)f;
if (field)
field->SetNDEString(nde_string);
}
CFStringRef NDE_StringField_GetString(nde_field_t f)
{
StringField *field = (StringField *)(Field *)f;
if (field)
return field->GetString();
else
return 0;
}
#endif
/* IntegerField functions */
void NDE_IntegerField_SetValue(nde_field_t f, int value)
{
IntegerField *field = (IntegerField *)(Field *)f;
if (field)
field->SetValue(value);
}
int NDE_IntegerField_GetValue(nde_field_t f)
{
IntegerField *field = (IntegerField *)(Field *)f;
if (field)
return field->GetValue();
else
return 0;
}
nde_field_t NDE_IntegerField_Create(int value)
{
return (nde_field_t)new IntegerField(value);
}
/* BinaryField */
void *NDE_BinaryField_GetData(nde_field_t f, size_t *length)
{
BinaryField *field = (BinaryField *)(Field *)f;
if (field)
return (void *)field->GetData(length);
else
return 0;
}
#ifdef __APPLE__
CFDataRef NDE_BinaryField_GetCFData(nde_field_t f)
{
BinaryField *field = (BinaryField *)(Field *)f;
if (field)
return field->GetCFData();
else
return 0;
}
#endif
void NDE_BinaryField_SetData(nde_field_t f, const void *data, size_t length)
{
BinaryField *field = (BinaryField *)(Field *)f;
if (field)
field->SetData((const uint8_t *)data, length);
}
/* Int128Field */
void NDE_Int128Field_SetValue(nde_field_t f, const void *value)
{
Int128Field *field = (Int128Field *)(Field *)f;
if (field && value)
field->SetValue(value);
}
/* ColumnField */
#ifdef _WIN32
const wchar_t *NDE_ColumnField_GetFieldName(nde_field_t f)
{
ColumnField *field = (ColumnField *)(Field *)f;
if (field)
return field->GetFieldName();
else
return 0;
}
#else
CFStringRef NDE_ColumnField_GetFieldName(nde_field_t f)
{
ColumnField *field = (ColumnField *)(Field *)f;
if (field)
return field->GetFieldName();
else
return 0;
}
#endif
unsigned char NDE_ColumnField_GetDataType(nde_field_t f)
{
ColumnField *field = (ColumnField *)(Field *)f;
if (field)
return field->GetDataType();
else
return FIELD_UNKNOWN;
}
#ifdef _WIN32
__time64_t NDE_Time_ApplyConversion(__time64_t value, const wchar_t *str, class TimeParse *tp)
{
IntegerField f(value);
f.ApplyConversion(str, tp);
return f.GetValue();
}
#endif

246
Src/nde/osx/nde_c.h Normal file
View file

@ -0,0 +1,246 @@
#pragma once
/* C style API.
We'll eventually deprecate the C++ API as it presents a lot of linking challenges
*/
#include "nde_defines.h"
#ifdef _WIN32
#include "NDEString.h"
#include <bfc/platform/types.h>
#endif
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __APPLE__
typedef time_t __time64_t; // TODO: find a way to do native 64bit time values
#endif
typedef struct nde_database_struct_t { } *nde_database_t;
typedef struct nde_table_struct_t { } *nde_table_t;
typedef struct nde_scanner_t_struct_t { } *nde_scanner_t;
typedef struct nde_field_t_struct_t { } *nde_field_t;
typedef struct nde_filter_struct_t { } *nde_filter_t;
/* Database functions */
// Windows API
#ifdef _WIN32
NDE_API void NDE_Init();
NDE_API void NDE_Quit();
#ifdef __cplusplus
NDE_API nde_database_t NDE_CreateDatabase(HINSTANCE hInstance=0);
#else
NDE_API nde_database_t NDE_CreateDatabase(HINSTANCE hInstance);
#endif
NDE_API void NDE_DestroyDatabase(nde_database_t db);
NDE_API nde_table_t NDE_Database_OpenTable(nde_database_t db, const wchar_t *filename, const wchar_t *filename_index, int create, int cache);
NDE_API void NDE_Database_CloseTable(nde_database_t db, nde_table_t table);
/* Table functions */
NDE_API nde_field_t NDE_Table_NewColumn(nde_table_t table, unsigned char id, const char *name, unsigned char type);
NDE_API void NDE_Table_PostColumns(nde_table_t table);
NDE_API void NDE_Table_AddIndexByID(nde_table_t table, unsigned char id, const char *name);
NDE_API nde_scanner_t NDE_Table_CreateScanner(nde_table_t table);
NDE_API void NDE_Table_DestroyScanner(nde_table_t table, nde_scanner_t scanner);
NDE_API void NDE_Table_Sync(nde_table_t table);
#ifdef __cplusplus
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress=0);
#else
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress);
#endif
NDE_API int NDE_Table_GetRecordsCount(nde_table_t table);
NDE_API nde_field_t NDE_Table_GetColumnByID(nde_table_t table, unsigned char id);
#ifdef _WIN32
NDE_API nde_field_t NDE_Table_GetColumnByName(nde_table_t table, const char *name);
#else
NDE_API nde_field_t NDE_Table_GetColumnByName(nde_table_t table, CFStringRef name);
#endif
NDE_API void NDE_Table_SetColumnSearchableByID(nde_table_t table, unsigned char id, int searchable);
/* Scanner functions */
NDE_API int NDE_Scanner_Query(nde_scanner_t scanner, const wchar_t *query);
NDE_API void NDE_Scanner_Search(nde_scanner_t scanner, const wchar_t *search_term);
NDE_API const wchar_t *NDE_Scanner_GetLastQuery(nde_scanner_t scanner);
NDE_API int NDE_Scanner_GetRecordsCount(nde_scanner_t scanner);
NDE_API void NDE_Scanner_New(nde_scanner_t scanner);
NDE_API void NDE_Scanner_Post(nde_scanner_t scanner);
#ifdef __cplusplus
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch=0);
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch=0);
#else
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch);
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch);
#endif
NDE_API void NDE_Scanner_Delete(nde_scanner_t scanner);
NDE_API void NDE_Scanner_Edit(nde_scanner_t scanner);
NDE_API int NDE_Scanner_EOF(nde_scanner_t scanner);
NDE_API int NDE_Scanner_BOF(nde_scanner_t scanner);
NDE_API nde_field_t NDE_Scanner_NewFieldByID(nde_scanner_t scanner, unsigned char id);
NDE_API nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t scanner, const char *name);
NDE_API nde_field_t NDE_Scanner_GetFieldByID(nde_scanner_t scanner, unsigned char id);
NDE_API nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t scanner, const char *name);
NDE_API void NDE_Scanner_AddFilterByID(nde_scanner_t scanner, unsigned char id, nde_field_t field, unsigned char filter_operation);
#ifdef __cplusplus
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
#else
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip, int compare_mode);
#endif
NDE_API void NDE_Scanner_DeleteField(nde_scanner_t scanner, nde_field_t field);
NDE_API void NDE_Scanner_RemoveFilters(nde_scanner_t scanner);
/* Filter functions */
NDE_API unsigned char NDE_Filter_GetID(nde_filter_t filter);
NDE_API unsigned char NDE_Filter_GetOp(nde_filter_t filter);
NDE_API nde_field_t NDE_Filter_GetData(nde_filter_t filter);
/* Field functions */
NDE_API unsigned char NDE_Field_GetType(nde_field_t field);
NDE_API unsigned char NDE_Field_GetID(nde_field_t field);
/* String Field functions */
NDE_API wchar_t *NDE_StringField_GetString(nde_field_t field); /* returns non-const because it's an NDE string (reference counted, see ndestring.h) */
NDE_API void NDE_StringField_SetNDEString(nde_field_t field, wchar_t *nde_string);
NDE_API void NDE_StringField_SetString(nde_field_t field, const wchar_t *str);
/* IntegerField functions */
NDE_API void NDE_IntegerField_SetValue(nde_field_t field, int value);
NDE_API int NDE_IntegerField_GetValue(nde_field_t field);
NDE_API nde_field_t NDE_IntegerField_Create(int value); /* mainly used for NDE_Scanner_AddFilterByID */
/* BinaryField functions */
// on windows, the data pointer is optionally reference counted via ndestring (ndestring_retain if you plan on keeping it)
NDE_API void *NDE_BinaryField_GetData(nde_field_t field, size_t *length);
NDE_API void NDE_BinaryField_SetData(nde_field_t field, const void *data, size_t length);
/* Int128Field functions */
NDE_API void NDE_Int128Field_SetValue(nde_field_t field, const void *value);
/* ColumnField functions */
NDE_API const wchar_t *NDE_ColumnField_GetFieldName(nde_field_t field);
NDE_API unsigned char NDE_ColumnField_GetDataType(nde_field_t field);
NDE_API __time64_t NDE_Time_ApplyConversion(__time64_t value, const wchar_t *str, class TimeParse *tp);
#elif defined(__APPLE__) // Mac OS X API, uses CFStringRef for a lot of stuff
NDE_API void NDE_Init();
NDE_API void NDE_Quit();
NDE_API nde_database_t NDE_CreateDatabase();
NDE_API void NDE_DestroyDatabase(nde_database_t db);
NDE_API nde_table_t NDE_Database_OpenTable(nde_database_t db, const char *filename, const char *filename_index, int create, int cache);
NDE_API void NDE_Database_CloseTable(nde_database_t db, nde_table_t table);
/* Table functions */
NDE_API nde_field_t NDE_Table_NewColumn(nde_table_t table, unsigned char id, const char *name, unsigned char type);
NDE_API void NDE_Table_PostColumns(nde_table_t table);
NDE_API void NDE_Table_AddIndexByID(nde_table_t table, unsigned char id, const char *name);
NDE_API nde_scanner_t NDE_Table_CreateScanner(nde_table_t table);
NDE_API void NDE_Table_DestroyScanner(nde_table_t table, nde_scanner_t scanner);
NDE_API void NDE_Table_Sync(nde_table_t table);
#ifdef __cplusplus
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress=0);
#else
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress);
#endif
NDE_API int NDE_Table_GetRecordsCount(nde_table_t table);
NDE_API nde_field_t NDE_Table_GetColumnByID(nde_table_t table, unsigned char id);
#ifdef _WIN32
NDE_API nde_field_t NDE_Table_GetColumnByName(nde_table_t table, const char *name);
#else
NDE_API nde_field_t NDE_Table_GetColumnByName(nde_table_t table, CFStringRef name);
#endif
/* Scanner functions */
NDE_API int NDE_Scanner_Query(nde_scanner_t scanner, const wchar_t *query);
NDE_API CFStringRef NDE_Scanner_GetLastQuery(nde_scanner_t scanner);
NDE_API int NDE_Scanner_GetRecordsCount(nde_scanner_t scanner);
NDE_API void NDE_Scanner_New(nde_scanner_t scanner);
NDE_API void NDE_Scanner_Post(nde_scanner_t scanner);
#ifdef __cplusplus
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch=0);
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch=0);
#else
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch);
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch);
#endif
NDE_API void NDE_Scanner_Delete(nde_scanner_t scanner);
NDE_API void NDE_Scanner_Edit(nde_scanner_t scanner);
NDE_API int NDE_Scanner_EOF(nde_scanner_t scanner);
NDE_API int NDE_Scanner_BOF(nde_scanner_t scanner);
NDE_API nde_field_t NDE_Scanner_NewFieldByID(nde_scanner_t scanner, unsigned char id);
NDE_API nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t scanner, const char *name);
NDE_API nde_field_t NDE_Scanner_GetFieldByID(nde_scanner_t scanner, unsigned char id);
NDE_API nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t scanner, const char *name);
NDE_API void NDE_Scanner_AddFilterByID(nde_scanner_t scanner, unsigned char id, nde_field_t field, unsigned char filter_operation);
#ifdef __cplusplus
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
#else
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode);
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip, int compare_mode);
#endif
NDE_API void NDE_Scanner_DeleteField(nde_scanner_t scanner, nde_field_t field);
NDE_API void NDE_Scanner_RemoveFilters(nde_scanner_t scanner);
/* Filter functions */
NDE_API unsigned char NDE_Filter_GetID(nde_filter_t filter);
NDE_API unsigned char NDE_Filter_GetOp(nde_filter_t filter);
NDE_API nde_field_t NDE_Filter_GetData(nde_filter_t filter);
/* Field functions */
NDE_API unsigned char NDE_Field_GetType(nde_field_t field);
NDE_API unsigned char NDE_Field_GetID(nde_field_t field);
/* String Field functions */
NDE_API CFStringRef NDE_StringField_GetString(nde_field_t field); /* returns non-const because it's an NDE string (reference counted, see ndestring.h) */
NDE_API void NDE_StringField_SetString(nde_field_t field, CFStringRef string);
/* IntegerField functions */
NDE_API void NDE_IntegerField_SetValue(nde_field_t field, int value);
NDE_API int NDE_IntegerField_GetValue(nde_field_t field);
NDE_API nde_field_t NDE_IntegerField_Create(int value); /* mainly used for NDE_Scanner_AddFilterByID */
/* BinaryField functions */
NDE_API void *NDE_BinaryField_GetData(nde_field_t field, size_t *length);
NDE_API CFDataRef NDE_BinaryField_GetCFData(nde_field_t field);
NDE_API void NDE_BinaryField_SetData(nde_field_t field, const void *data, size_t length);
/* Int128Field functions */
NDE_API void NDE_Int128Field_SetValue(nde_field_t field, const void *value);
/* ColumnField functions */
#ifdef _WIN32
NDE_API const char *NDE_ColumnField_GetFieldName(nde_field_t field);
#else
NDE_API CFStringRef NDE_ColumnField_GetFieldName(nde_field_t field);
#endif
NDE_API unsigned char NDE_ColumnField_GetDataType(nde_field_t field);
NDE_API __time64_t NDE_Time_ApplyConversion(__time64_t value, const wchar_t *str, class TimeParse *tp);
#endif
#ifdef __cplusplus
}
#endif