dmose%mozilla.org 0efb7c174c updated xPL license boilerplate to v1.1, a=chofmann@netscape.com,r=endico@mozilla.org
git-svn-id: svn://10.0.0.236/trunk@52910 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-06 03:43:54 +00:00

1207 lines
28 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*
This file (which should probably be called rdf.c) implements the
core rdf query mechanism.
For more information on this file, contact rjc or guha
For more information on RDF, look at the RDF section of www.mozilla.org
*/
#include "mcf.h"
#include "columns.h"
#include "find2rdf.h"
#include "fs2rdf.h"
#include "hist2rdf.h"
#include "nlcstore.h"
#include "remstore.h"
#include "es2mcf.h"
#include "pm2rdf.h"
#include "scook.h"
#include "atalk.h"
#include "ht.h"
#include "utils.h"
#ifdef DEBUG_guha
#define SMART_MAIL 1
#endif
/* globals */
RDFL gAllDBs = 0;
RDFT
getTranslator (char* url)
{
RDFT ans = PL_HashTableLookup(dataSourceHash, url);
if (ans) return ans;
#ifdef MOZILLA_CLIENT
if (startsWith(url, "rdf:localStore")) {
ans = MakeLocalStore(url);
} else
#endif
if (startsWith(url, "rdf:remoteStore")) {
ans = MakeRemoteStore(url);
}
#ifdef MOZILLA_CLIENT
else if (startsWith(url, "rdf:history")) {
ans = MakeHistoryStore(url);
} else if (startsWith(url, "rdf:esftp")) {
ans = MakeESFTPStore(url);
/* } else if (startsWith(url, "rdf:mail")) {
ans = MakeMailStore(url); */
} else if (startsWith(url, "rdf:lfs")) {
ans = MakeLFSStore(url);
#ifdef XP_MAC
} else if (startsWith(url, "rdf:appletalk")) {
ans = MakeAtalkStore(url);
#endif
} else if (strstr(url, ".rdf") || strstr(url, ".RDF") ||
strstr(url, ".mcf") || strstr(url, ".MCF")) {
ans = MakeFileDB(url);
} else if (startsWith("rdf:columns", url)) {
ans = MakeColumnStore (url);
} else if (startsWith("rdf:ht", url) || startsWith("rdf:scook", url)) {
ans = MakeSCookDB(url);
} else if (startsWith("rdf:CookieStore", url)) {
ans = MakeCookieStore(url);
} else if (startsWith("rdf:find", url)) {
ans = MakeFindStore(url);
}
#endif
else if (startsWith("http://", url)) {
ans = MakeFileDB(url);
} else if (startsWith("mailbox://", url)){
#ifdef SMART_MAIL
ans = MakePopDB(url);
#else
ans = NULL;
#endif
} else if (startsWith("mailaccount://", url)) {
#ifdef SMART_MAIL
ans = MakeMailAccountDB(url);
#else
ans = NULL;
#endif
} else {
ans = NULL;
}
#ifdef MOZILLA_CLIENT
#ifdef DEBUG
{
char* traceLine = getMem(500);
sprintf(traceLine, "\nCreated %s \n", url);
FE_Trace(traceLine);
freeMem(traceLine);
}
#endif
#endif
if (ans) PL_HashTableAdd(dataSourceHash, ans->url, ans);
return ans;
}
PR_PUBLIC_API(RDF)
RDF_GetDB (const char** dataSources)
{
int32 n = 0;
int32 m = 0;
char* next ;
RDF r = (RDF) getMem(sizeof(struct RDF_DBStruct)) ;
RDFL nrl = (RDFL)getMem(sizeof(struct RDF_ListStruct));
while (*(dataSources + n++)) {}
r->translators = (RDFT*)getMem((n) * sizeof(RDFT));
n = 0;
while ((next = (char*) *(dataSources + n)) != NULL) {
RDFL rl = (RDFL)getMem(sizeof(struct RDF_ListStruct));
r->translators[m] = getTranslator(next);
if (r->translators[m] != NULL) {
rl->rdf = r;
rl->next = r->translators[m]->rdf;
r->translators[m]->rdf = rl;
m++;
} else {
freeMem(rl);
/* r->numTranslators = m;
r->translatorArraySize = n;
RDF_ReleaseDB(r);
return NULL; */
}
n++;
}
r->numTranslators = m;
r->translatorArraySize = n;
nrl->rdf = r;
nrl->next = gAllDBs;
gAllDBs = nrl;
return r;
}
PR_PUBLIC_API(RDFT)
RDF_AddDataSource(RDF rdf, char* dataSource)
{
RDFT newDB;
int32 n = 0;
RDFT next;
while (((next = rdf->translators[n++]) != NULL) && (n < rdf->numTranslators)) {
if (strcmp(next->url, dataSource) == 0) return next;
}
#ifdef MOZILLA_CLIENT
#ifdef DEBUG
{
char* traceLine = getMem(500);
sprintf(traceLine, "\nAdding %s \n", dataSource);
FE_Trace(traceLine);
freeMem(traceLine);
}
#endif
#endif
if (rdf->numTranslators >= rdf->translatorArraySize) {
RDFT* tmp = (RDFT*)getMem((rdf->numTranslators+5)*(sizeof(RDFT)));
memcpy(tmp, rdf->translators, (rdf->numTranslators * sizeof(RDFT)));
rdf->translatorArraySize = rdf->numTranslators + 5;
freeMem(rdf->translators);
rdf->translators = tmp;
}
newDB = getTranslator(dataSource);
if (!newDB) {
return NULL;
} else {
RDFL rl = (RDFL)getMem(sizeof(struct RDF_ListStruct));
RDFT tr = rdf->translators[rdf->numTranslators];
rl->rdf = rdf;
rl->next = newDB->rdf;
newDB->rdf = rl;
rdf->translators[rdf->numTranslators] = newDB;
rdf->numTranslators++;
return newDB;
}
}
PR_PUBLIC_API(RDF_Error)
RDF_ReleaseDataSource(RDF rdf, RDFT dataSource)
{
RDFT* temp = (RDFT*)getMem((rdf->numTranslators-1)*(sizeof(RDFT)));
int32 m = 0;
int32 n= 0;
RDFT next;
while ((next = rdf->translators[n++]) != NULL) {
if (next != dataSource) {
*(temp + m++) = (RDFT) next;
}
}
memset(rdf->translators, '\0', sizeof(RDFT) * rdf->numTranslators);
memcpy(rdf->translators, temp, sizeof(RDFT) * (rdf->numTranslators -1));
rdf->numTranslators--;
dataSource->rdf = deleteFromRDFList(dataSource->rdf, rdf);
if ((dataSource->rdf == NULL) && (dataSource->destroy != NULL)) {
PL_HashTableRemove(dataSourceHash, dataSource->url);
(*dataSource->destroy)(dataSource);
}
return 0;
}
RDFL
deleteFromRDFList (RDFL xrl, RDF db)
{
RDFL rl = xrl;
RDFL prev = rl;
while (rl) {
if (rl->rdf == db) {
if (prev == rl) {
RDFL ans = rl->next;
freeMem(rl);
return ans;
} else {
prev->next = rl->next;
freeMem(rl);
return xrl;
}
}
prev = rl;
rl = rl->next;
}
return xrl;
}
void
disposeAllDBs ()
{
while (gAllDBs) {
RDF_ReleaseDB(gAllDBs->rdf);
}
}
PR_PUBLIC_API(RDF_Error)
RDF_ReleaseDB(RDF rdf)
{
if (rdf != NULL) {
uint32 n = 0;
uint32 size = rdf->numTranslators;
while (n < size) {
RDFT rdft = (*((RDFT*)rdf->translators + n));
RDFL rlx ;
if (rdft) {
rlx = rdft->rdf;
rdft->rdf = deleteFromRDFList(rlx, rdf);
if (rdft->rdf == NULL) callExitRoutine(n, rdf);
}
n++;
}
gAllDBs = deleteFromRDFList(gAllDBs, rdf);
}
freeMem(rdf->translators);
freeMem(rdf);
return noRDFErr;
}
RDF_Resource
addDep (RDF db, RDF_Resource u)
{
if (db) {
RDFL rl = u->rdf;
while (rl) {
if (rl->rdf == db) return u;
rl = rl->next;
}
rl = (RDFL) getMem(sizeof(struct RDF_ListStruct));
rl->rdf = db;
rl->next = u->rdf;
u->rdf = rl;
return u;
}
return u;
}
PRBool
rdfassert(RDF rdf, RDF_Resource u, RDF_Resource s, void* value,
RDF_ValueType type, PRBool tv)
{
int32 size = rdf->numTranslators;
int32 n = size -1;
XP_ASSERT( (type != RDF_STRING_TYPE ) || IsUTF8String((const char*)value));
/* XXX - what happens here if there is no local store? */
if ((size > 1) && (callHasAssertions(0, rdf, u, s, value, type, (!tv)))) {
setLockedp(u, 1);
callUnassert(0, rdf, u, s, value, type);
setLockedp(u, 0);
if (RDF_HasAssertion(rdf, u, s, value, type, tv)) return 1;
}
while (n > -1) {
if (callAssert(n, rdf, u, s, value, type, tv)) return 1;
n--;
}
return 0;
}
PR_PUBLIC_API(PRBool)
RDF_Assert (RDF rdf, RDF_Resource u, RDF_Resource s, void* value, RDF_ValueType type)
{
return rdfassert(rdf, u, s, value, type, 1);
}
PR_PUBLIC_API(PRBool)
RDF_AssertFalse (RDF rdf, RDF_Resource u, RDF_Resource s, void* value, RDF_ValueType type)
{
return rdfassert(rdf, u, s, value, type, 0);
}
PR_PUBLIC_API(PRBool)
RDF_CanAssert(RDF r, RDF_Resource u, RDF_Resource s,
void* v, RDF_ValueType type)
{
XP_ASSERT( (type != RDF_STRING_TYPE ) || IsUTF8String((const char*)v));
return true;
}
PR_PUBLIC_API(PRBool)
RDF_CanAssertFalse(RDF r, RDF_Resource u, RDF_Resource s, void* v, RDF_ValueType type)
{
XP_ASSERT( (type != RDF_STRING_TYPE ) || IsUTF8String((const char*)v));
return true;
}
PR_PUBLIC_API(PRBool)
RDF_CanUnassert(RDF r, RDF_Resource u, RDF_Resource s, void* v, RDF_ValueType type)
{
XP_ASSERT( (type != RDF_STRING_TYPE ) || IsUTF8String((const char*)v));
return true;
}
PR_PUBLIC_API(PRBool)
RDF_Unassert (RDF rdf, RDF_Resource u, RDF_Resource s, void* value, RDF_ValueType type)
{
PRBool allok = 1;
int32 size = rdf->numTranslators;
int32 n = 0;
XP_ASSERT( (type != RDF_STRING_TYPE ) || IsUTF8String((const char*)value));
setLockedp(u, 1);
while (allok && (n < size)) {
if (callHasAssertions(n, rdf, u, s, value, type, 1)) {
allok = callUnassert(n, rdf, u, s, value, type);
}
n++;
}
if (!allok) allok = callAssert(0, rdf, u, s, value, type, 0);
setLockedp(u, 0);
return allok;
}
PRBool
containerIDp(char* id)
{
return (endsWith(".rdf", id) || (endsWith(".mco", id)) || (endsWith(".mcf", id)) ||
strstr(id, ".rdf#"));
}
char *
makeNewID ()
{
PRTime tm = PR_Now();
char *id;
#ifndef HAVE_LONG_LONG
double doubletm;
#endif /* !HAVE_LONG_LONG */
id = (char *)getMem(ID_BUF_SIZE);
#ifdef HAVE_LONG_LONG
PR_snprintf(id, ID_BUF_SIZE, "%1.0f", (double)tm);
#else
LL_L2D(doubletm, tm);
PR_snprintf(id, ID_BUF_SIZE, "%1.0f", doubletm);
#endif /* HAVE_LONG_LONG */
/* prevent collisions by checking hash. */
while (PL_HashTableLookup(resourceHash, id) != NULL)
{
#ifdef HAVE_LONG_LONG
tm = tm + (PR_MSEC_PER_SEC * 60); /* fix me - not sure what the increment should be */
PR_snprintf(id, ID_BUF_SIZE, "%1.0f", (double)tm);
#else
int64 incr;
LL_I2L(incr, (PR_MSEC_PER_SEC * 60));
LL_ADD(tm, tm, incr);
LL_L2D(doubletm, tm);
PR_snprintf(id, ID_BUF_SIZE, "%1.0f", doubletm);
#endif /* HAVE_LONG_LONG */
}
return (id);
}
PRBool
iscontainerp (RDF_Resource u)
{
char* id = resourceID(u);
if (containerIDp(id)) {
return 1;
}
#ifdef MOZILLA_CLIENT
else if (startsWith("file:", id)) {
return (endsWith("/", id) || fileDirectoryp(u));
} else if (startsWith("ftp:", id) && (endsWith("/", id))) {
return 1;
} else if (startsWith("cache:container", id)) {
return 1;
} else if (startsWith("find:", id)) {
return 1;
}
#endif
else return 0;
}
RDF_BT
resourceTypeFromID (char* id)
{
if (endsWith(".rdf", id) || (strstr(id, ".rdf#"))) {
return RDF_RT;
} else if (endsWith(".mcf", id) || (strstr(id, ".mcf#"))) {
return RDF_RT;
} else if (endsWith(".mco", id)) {
return RDF_RT;
} else if (startsWith("file:", id)) {
return LFS_RT;
} else if (startsWith("nes:", id)) {
return ES_RT;
} else if (startsWith("ftp:", id)) {
return FTP_RT;
} else if (startsWith("cache:", id)) {
return CACHE_RT;
} else return 0;
}
RDF_Resource
specialUrlResource (char* id)
{
if (strcmp(id, "NC:PersonalToolbar") == 0)
return RDFUtil_GetPTFolder();
return NULL;
}
RDF_Resource
NewRDFResource (char* id)
{
RDF_Resource existing;
if ((existing = (RDF_Resource)getMem(sizeof(struct RDF_ResourceStruct))) != NULL)
{
existing->url = copyString(id);
PL_HashTableAdd(resourceHash, existing->url, existing);
}
return(existing);
}
RDF_Resource
QuickGetResource (char* id)
{
RDF_Resource existing;
if ((existing = (RDF_Resource)PL_HashTableLookup(resourceHash, id)) == NULL)
{
existing = NewRDFResource(id);
}
return(existing);
}
PR_PUBLIC_API(RDF_Resource)
RDF_GetResource (RDF db, char* id, PRBool createp)
{
char* nid = NULL;
RDF_Resource existing = NULL;
if (id == NULL) {
if (!createp) {
return NULL;
} else {
id = nid = makeNewID();
}
}
existing = specialUrlResource(id);
if (existing) return existing;
existing = (RDF_Resource)PL_HashTableLookup(resourceHash, id);
if (existing) return addDep(db, existing);
if (!createp) return NULL;
existing = NewRDFResource(id);
setResourceType(existing, resourceTypeFromID(id));
setContainerp(existing, iscontainerp(existing));
if (nid) freeMem(nid);
return addDep(db, existing);
}
PR_PUBLIC_API (RDF_Error)
RDF_DeleteAllArcs (RDF rdf, RDF_Resource u)
{
Assertion as, next;
/* if (u->locked) return -1; */
as = u->rarg1;
while (as != NULL) {
next = as->next;
remoteStoreRemove(gRemoteStore, as->u, as->s, as->value, as->type);
as = next;
}
as = u->rarg2;
while (as != NULL) {
next = as->invNext;
remoteStoreRemove(gRemoteStore, as->u, as->s, as->value, as->type);
as = next;
}
#if defined(DBMTEST) && defined(MOZILLA_CLIENT)
nlclStoreKill(gLocalStore, u);
#endif
return 0;
}
PR_PUBLIC_API(RDF_Error)
RDF_Update(RDF rdf, RDF_Resource u) {
int32 size = rdf->numTranslators;
int32 n = 0;
while (n < size) {
callUpdateRoutine(n, rdf, u);
n++;
}
return 0;
}
PR_PUBLIC_API(PRBool)
RDF_HasAssertion (RDF rdf, RDF_Resource u, RDF_Resource s,
void* v, RDF_ValueType type, PRBool tv)
{
int32 size = rdf->numTranslators;
int32 n = 0;
XP_ASSERT( (type != RDF_STRING_TYPE ) || IsUTF8String((const char*)v));
if (callHasAssertions(0, rdf, u, s, v, type, !tv)) return 0;
while (n < size) {
if (callHasAssertions(n, rdf, u, s, v, type, tv)) return 1;
n++;
}
return 0;
}
PR_PUBLIC_API(void *)
RDF_GetSlotValue (RDF rdf, RDF_Resource u, RDF_Resource s,
RDF_ValueType type, PRBool inversep, PRBool tv)
{
int32 size = rdf->numTranslators;
int32 n = 0;
if ((s == gWebData->RDF_URL) && (tv) && (!inversep) && (type == RDF_STRING_TYPE))
return copyString(resourceID(u));
while (n < size) {
RDFT translator = rdf->translators[n];
void* ans = callGetSlotValue(n, rdf, u, s, type, inversep, tv);
if ((ans != NULL) && ((n == 0)||(!callHasAssertions(0, rdf, u, s, ans, type, !tv))))
{
XP_ASSERT( (type != RDF_STRING_TYPE ) || IsUTF8String((const char*)ans));
if (type == RDF_RESOURCE_TYPE) {
return addDep(rdf, ans) ;
} else {
return ans;
}
}
n++;
}
if (s == gCoreVocab->RDF_name && tv && !inversep && type == RDF_STRING_TYPE)
return makeResourceName(u);
return NULL;
}
RDFT
RDFTNamed (RDF rdf, char* name)
{
int32 size = rdf->numTranslators;
int32 n = 0;
while (n < size) {
char* nn = (*((RDFT*)rdf->translators + n))->url;
if (strcmp(nn, name) == 0) return (*((RDFT*)rdf->translators + n));
n = n + 1;
}
return NULL;
}
RDF_Cursor
getSlotValues (RDF rdf, RDF_Resource u, RDF_Resource s,
RDF_ValueType type, PRBool inversep, PRBool tv)
{
RDF_Cursor c = (RDF_Cursor) getMem(sizeof(struct RDF_CursorStruct));
if (c == NULL) return(NULL);
c->u = u;
c->s = s;
c->queryType = RDF_GET_SLOT_VALUES_QUERY;
c->tv = tv;
c->inversep = inversep;
c->type = type;
c->count = -1;
c->rdf = rdf;
c->current = NULL;
while ((c->count < rdf->numTranslators-1) && (!c->current)) {
c->count++;
c->current = callGetSlotValues(c->count, rdf, u, s, type, inversep, tv);
}
if (!c->current) {
freeMem(c);
return NULL;
} else {
return c;
}
}
PR_PUBLIC_API(RDF_Cursor)
RDF_GetTargets (RDF rdfDB, RDF_Resource source, RDF_Resource arcLabel,
RDF_ValueType targetType, PRBool tv)
{
return getSlotValues(rdfDB, source, arcLabel, targetType, 0, tv);
}
PR_PUBLIC_API(RDF_Cursor)
RDF_GetSources (RDF rdfDB, RDF_Resource target, RDF_Resource arcLabel,
RDF_ValueType sourceType, PRBool tv)
{
if (sourceType != RDF_RESOURCE_TYPE) return NULL;
return getSlotValues(rdfDB, target, arcLabel, sourceType, 1, tv);
}
PR_PUBLIC_API(RDF_ValueType)
RDF_CursorValueType(RDF_Cursor c)
{
if (c == NULL) {
return 0;
} else {
return c->type;
}
}
PR_PUBLIC_API(char*)
RDF_ValueDataSource(RDF_Cursor c)
{
if (c == NULL) {
return NULL;
} else {
RDF rdf = c->rdf;
RDFT rdft;
if (rdf == NULL) return NULL;
rdft = rdf->translators[c->count];
if (rdft) {
return rdft->url;
} else {
return NULL;
}
}
}
PR_PUBLIC_API(RDF_Cursor)
RDF_ArcLabelsOut (RDF rdfDB, RDF_Resource u)
{
RDF_Cursor c = (RDF_Cursor) getMem(sizeof(struct RDF_CursorStruct));
if (c == NULL) return(NULL);
c->u = u;
c->queryType = RDF_ARC_LABELS_OUT_QUERY;
c->type = RDF_RESOURCE_TYPE;
c->count = -1;
c->rdf = rdfDB;
c->current = NULL;
while ((c->count < rdfDB->numTranslators-1) && (!c->current)) {
c->count++;
c->current = callArcLabelsOut(c->count, rdfDB, u);
}
if (!c->current) {
freeMem(c);
return NULL;
} else {
return c;
}
}
PR_PUBLIC_API(RDF_Cursor)
RDF_ArcLabelsIn (RDF rdfDB, RDF_Resource u)
{
RDF_Cursor c = (RDF_Cursor) getMem(sizeof(struct RDF_CursorStruct));
if (c == NULL) return(NULL);
c->u = u;
c->queryType = RDF_ARC_LABELS_IN_QUERY;
c->type = RDF_RESOURCE_TYPE;
c->count = -1;
c->rdf = rdfDB;
c->current = NULL;
while ((c->count < rdfDB->numTranslators-1) && (!c->current)) {
c->count++;
c->current = callArcLabelsIn(c->count, rdfDB, u);
}
if (!c->current) {
freeMem(c);
return NULL;
} else {
return c;
}
}
PR_PUBLIC_API(void *)
RDF_NextValue (RDF_Cursor c)
{
void* ans;
RDF rdf;
if (c == NULL) return NULL;
if (c->queryType == RDF_FIND_QUERY) return nextFindValue(c);
rdf = c->rdf;
ans = (*rdf->translators[c->count]->nextValue)(rdf->translators[c->count], c->current);
while (ans != NULL) {
if ((c->count == 0) || (c->queryType != RDF_GET_SLOT_VALUES_QUERY)) {
if (c->type == RDF_RESOURCE_TYPE) return addDep(c->rdf, ans);
else return ans;
}
if (((!c->inversep) &&
(!(callHasAssertions(0, rdf, c->u, c->s, ans, c->type, !c->tv)))) ||
((c->inversep) &&
(!(callHasAssertions(0, rdf, (RDF_Resource)ans, c->s, c->u,
c->type, !c->tv))))) {
if (c->type == RDF_RESOURCE_TYPE) {
return addDep(c->rdf, (RDF_Resource)ans);
} else return ans;
}
ans = (*rdf->translators[c->count]->nextValue)(rdf->translators[c->count], c->current);
}
(*rdf->translators[c->count]->disposeCursor)(rdf->translators[c->count], c->current);
c->current = NULL;
while ((c->count < rdf->numTranslators - 1) && (!c->current)) {
c->count++;
switch (c->queryType) {
case RDF_GET_SLOT_VALUES_QUERY :
c->current = callGetSlotValues(c->count,rdf, c->u, c->s, c->type,
c->inversep, c->tv);
break;
case RDF_ARC_LABELS_OUT_QUERY :
c->current = callArcLabelsOut(c->count, rdf, c->u);
break;
case RDF_ARC_LABELS_IN_QUERY :
c->current = callArcLabelsIn(c->count, rdf, c->u);
break;
}
}
if (c->current == NULL) return NULL;
return RDF_NextValue(c);
}
void
disposeResourceInt (RDF rdf, RDF_Resource u)
{
int32 size = rdf->numTranslators;
int32 n = 0;
PRBool ok = 1;
while (n < size && ok) {
ok = (callDisposeResource(n, rdf, u));
n++;
}
if (ok && (!lockedp(u))) possiblyGCResource(u);
}
PR_PUBLIC_API(RDF_Error)
RDF_ReleaseResource (RDF db, RDF_Resource u)
{
if (db && u) {
u->rdf = deleteFromRDFList(u->rdf, db);
if (u->rdf == NULL) disposeResourceInt(db, u);
}
return 0;
}
PR_PUBLIC_API(RDF_Error)
RDF_DisposeCursor (RDF_Cursor c)
{
if ((c != NULL) && (c->queryType == RDF_FIND_QUERY) && (c->pdata)) freeMem(c->pdata);
if (c != NULL) freeMem(c);
return 0;
}
PRIntn
findEnumerator (PLHashEntry *he, PRIntn i, void *arg)
{
RDF_Cursor c = (RDF_Cursor) arg;
RDF_Resource u = (RDF_Resource)he->value;
if (itemMatchesFind(c->rdf, u, c->s, c->value, c->match, c->type)) {
/* if (c->size <= c->count) */ {
RDF_Resource* newBlock = getMem(c->size + sizeof(RDF_Resource *));
if (newBlock == NULL) return HT_ENUMERATE_STOP;
if (c->size > 0) {
memcpy(newBlock, c->pdata, c->size);
freeMem(c->pdata);
}
c->pdata = newBlock;
c->size += sizeof(RDF_Resource *);
}
*((RDF_Resource*)(((char *)c->pdata) + (c->count*sizeof(RDF_Resource *)))) = u;
c->count++;
}
return HT_ENUMERATE_NEXT;
}
PR_PUBLIC_API(RDF_Cursor)
RDF_Find (RDF_Resource s, RDF_Resource match, void* v, RDF_ValueType type)
{
RDF_Cursor c = (RDF_Cursor) getMem(sizeof(struct RDF_CursorStruct));
XP_ASSERT( (type != RDF_STRING_TYPE ) || IsUTF8String((const char*)v));
c->s = s;
c->match = match;
c->value = v;
c->type = type;
c->queryType = RDF_FIND_QUERY;
c->rdf = gAllDBs->rdf;
PL_HashTableEnumerateEntries(resourceHash, findEnumerator, c);
c->count = 0;
return c;
}
PRBool
matchStrings(RDF_Resource match, char *data, char *pattern)
{
PRBool ok = 0;
if (match == NULL) match = gCoreVocab->RDF_substring;
if (match == gCoreVocab->RDF_substring)
{
ok = substring(pattern, data);
}
else if (match == gCoreVocab->RDF_stringEquals)
{
ok = (PRBool)(!compareStrings(data, pattern));
}
else if (match == gCoreVocab->RDF_stringNotEquals)
{
ok = (PRBool)compareStrings(data, pattern);
}
else if (match == gCoreVocab->RDF_stringStartsWith)
{
ok = startsWith(pattern, data);
}
else if (match == gCoreVocab->RDF_stringEndsWith)
{
ok = endsWith(pattern, data);
}
return(ok);
}
PRBool
itemMatchesFind (RDF r, RDF_Resource u, RDF_Resource s, void* v,
RDF_Resource match, RDF_ValueType type)
{
RDF_Cursor c;
void *val;
PRBool ok = 0;
if ((s == gWebData->RDF_URL) && (type == RDF_STRING_TYPE))
{
val = resourceID(u);
ok = matchStrings(match, val, v);
return(ok);
}
c = RDF_GetTargets(r, u, s, type, 1);
if (c != NULL) {
while ((val = RDF_NextValue(c)) != NULL) {
if (type == RDF_RESOURCE_TYPE) {
ok = (u == v);
} else if (type == RDF_STRING_TYPE) {
if (s == gWebData->RDF_URL)
{
val = resourceID(u);
}
ok = matchStrings(match, val, v);
}
if (ok) {
RDF_DisposeCursor(c);
return 1;
}
}
RDF_DisposeCursor(c);
}
return 0;
}
RDF_Resource
nextFindValue (RDF_Cursor c)
{
RDF_Resource ans = NULL;
if (((c->count*sizeof(RDF_Resource *)) < c->size) &&
(*(RDF_Resource *)((char *)c->pdata + (c->count*sizeof(RDF_Resource *))) != NULL))
{
ans = *(RDF_Resource *)((char *)c->pdata + (c->count*sizeof(RDF_Resource *)));
c->count++;
}
return ans;
}
void
possiblyGCResource (RDF_Resource u)
{
if ((nullp(u->pdata)) && (nullp(u->rarg1)) && (nullp(u->rarg2))) {
PL_HashTableRemove(resourceHash, resourceID(u));
freeMem(u->url);
freeMem(u);
}
}
PR_PUBLIC_API(RDF_Notification)
RDF_AddNotifiable (RDF rdfDB, RDF_NotificationProc callBack,
RDF_Event ev, void* pdata)
{
RDF_Notification ns = (RDF_Notification)getMem(sizeof(struct RDF_NotificationStruct));
RDF_Event nev = (RDF_Event)getMem(sizeof(struct RDF_EventStruct));
memcpy((char*)nev, ev, sizeof(struct RDF_EventStruct));
ns->theEvent = nev;
ns->notifFunction = callBack;
ns->pdata = pdata;
ns->next = rdfDB->notifs;
rdfDB->notifs = ns;
ns->rdf = rdfDB;
return ns;
}
PR_PUBLIC_API(RDF_Error)
RDF_DeleteNotifiable (RDF_Notification ns)
{
RDF rdf = ns->rdf;
RDF_Notification pr = rdf->notifs;
RDF_Notification not;
if (pr == ns) {
rdf->notifs = pr->next;
} else {
for (not = rdf->notifs; (not != NULL) ; not = not->next) {
if (ns == not)
{
pr->next = not->next;
break;
}
pr = not;
}
}
freeMem(ns->theEvent);
freeMem(ns);
return 0;
}
void
assertNotify (RDF rdf, RDF_Notification not, RDF_Resource u, RDF_Resource s, void* v, RDF_ValueType type, PRBool tv, char* ds)
{
RDF_Event nev = not->theEvent;
RDF_AssertEvent ev = &(not->theEvent->event.assert);
PRBool opTypeFixed = not->theEvent->eventType;
PRBool uFixed = (ev->u != NULL);
PRBool sFixed = (ev->s != NULL);
PRBool vFixed = (ev->v != NULL);
RDF_EventType oldEventType = not->theEvent->eventType;
if ((!opTypeFixed ||(not->theEvent->eventType & RDF_ASSERT_NOTIFY)) &&
(!uFixed || (ev->u == u)) &&
(!vFixed || (ev->v == v)) &&
(!sFixed || (ev->s == s))) {
/* if (callHasAssertions(0, rdf, u, s, v, type, !tv)) return; */
nev->eventType = RDF_ASSERT_NOTIFY;
ev->u = u;
ev->s = s;
ev->v = v;
ev->type = type;
ev->tv = tv;
ev->dataSource = ds;
(*(not->notifFunction))(nev, not->pdata);
nev->eventType = oldEventType;
if (!uFixed) ev->u = NULL;
if (!sFixed) ev->s = NULL;
if (!vFixed) ev->v = NULL;
}
}
void
insertNotify (RDF rdf, RDF_Notification not, RDF_Resource u, RDF_Resource s, void* v, RDF_ValueType type, PRBool tv, char* ds)
{
RDF_Event nev = not->theEvent;
RDF_AssertEvent ev = &(not->theEvent->event.assert);
PRBool opTypeFixed = not->theEvent->eventType;
PRBool uFixed = (ev->u != NULL);
PRBool sFixed = (ev->s != NULL);
PRBool vFixed = (ev->v != NULL);
RDF_EventType oldEventType = not->theEvent->eventType;
if ((!opTypeFixed ||(not->theEvent->eventType & RDF_INSERT_NOTIFY)) &&
(!uFixed || (ev->u == u)) &&
(!vFixed || (ev->v == v)) &&
(!sFixed || (ev->s == s))) {
/* if (callHasAssertions(0, rdf, u, s, v, type, !tv)) return; */
nev->eventType = RDF_INSERT_NOTIFY;
ev->u = u;
ev->s = s;
ev->v = v;
ev->type = type;
ev->tv = tv;
ev->dataSource = ds;
(*(not->notifFunction))(nev, not->pdata);
nev->eventType = oldEventType;
if (!uFixed) ev->u = NULL;
if (!sFixed) ev->s = NULL;
if (!vFixed) ev->v = NULL;
}
}
void
unassertNotify (RDF_Notification not, RDF_Resource u, RDF_Resource s, void* v, RDF_ValueType type, char* ds)
{
RDF_Event nev = not->theEvent;
RDF_UnassertEvent ev = &(not->theEvent->event.unassert);
PRBool opTypeFixed = not->theEvent->eventType;
PRBool uFixed = (ev->u != NULL);
PRBool sFixed = (ev->s != NULL);
PRBool vFixed = (ev->v != NULL);
RDF_EventType oldEventType = not->theEvent->eventType;
if ((!opTypeFixed ||(not->theEvent->eventType & RDF_DELETE_NOTIFY)) &&
(!uFixed || (ev->u == u)) &&
(!vFixed || (ev->v == v)) &&
(!sFixed || (ev->s == s))) {
nev->eventType = RDF_DELETE_NOTIFY;
ev->u = u;
ev->s = s;
ev->v = v;
ev->type = type;
ev->dataSource = ds;
(*(not->notifFunction))(nev, not->pdata);
nev->eventType = oldEventType;
if (!uFixed) ev->u = NULL;
if (!sFixed) ev->s = NULL;
if (!vFixed) ev->v = NULL;
}
}
void
sendNotifications2 (RDFT r, RDF_EventType opType, RDF_Resource u, RDF_Resource s, void* v, RDF_ValueType type, PRBool tv)
{
RDFL rl = r->rdf;
if ((opType == RDF_ASSERT_NOTIFY) && gLocalStore &&
(nlocalStoreHasAssertion(gLocalStore, u, s, v, type, !tv))) {
return;
}
while (rl) {
sendNotifications(rl->rdf, opType, u, s, v, type, tv, r->url);
rl = rl->next;
}
}
void
sendNotifications (RDF rdf, RDF_EventType opType, RDF_Resource u, RDF_Resource s, void* v, RDF_ValueType type, PRBool tv, char* ds)
{
RDF_Notification not;
if (rdf == NULL) return;
for (not = rdf->notifs; (not != NULL) ; not = not->next) {
if (!not->theEvent || (not->theEvent->eventType & opType)) {
RDF_EventType otype = not->theEvent->eventType;
switch (opType)
{
case RDF_ASSERT_NOTIFY :
assertNotify(rdf, not, u, s, v, type, tv, ds);
break;
case RDF_INSERT_NOTIFY :
insertNotify(rdf, not, u, s, v, type, tv, ds);
break;
case RDF_DELETE_NOTIFY :
unassertNotify(not, u, s, v, type, ds);
break;
case RDF_KILL_NOTIFY :
break;
/* killNotify(not, u); */
}
not->theEvent->eventType = otype;
}
}
}