Esempio n. 1
0
/*
 *	Set a node's data.  If it does not exist, create it.
 *	Return a pointer to the node.
 */
DLLEXP struct pdb_node_t* pdb_set_node(struct pdb* dbptr, char* path, char* key,
	void* data, int type) {

	struct pdb_node_types_t* tiptr;
	struct pdb_node_t* pptr;
	struct pdb_node_types_t* ptiptr;
	struct pdb_node_t* nptr;

	if (!dbptr)
		return NULL;

	PDB_MUTEX_LOCK(dbptr);

	tiptr = pdb_get_type_info(type);
	if (!tiptr) {
		PDB_MUTEX_UNLOCK(dbptr);
		return NULL;
	}
	
	PDB_MUTEX_UNLOCK(dbptr);
	pptr = pdb_query_node(dbptr, path);

	if (!pptr)
		return NULL;

	PDB_MUTEX_LOCK(dbptr);
	
	ptiptr = pdb_get_type_info(pptr->type);
	nptr = ptiptr->query_cb(pptr, key);
		
	if (!nptr) {
		/*
		 *	Node does not exists -- create.
		 */
		nptr = tiptr->create_cb(key, pptr, NULL);
		if (!nptr) {
			fprintf(stderr, "%s:%s():%i: Error: Unable to create \"%s/%s\" in "
				"database.\n", __FILE__, __FUNCTION__, __LINE__, path, key);
			PDB_MUTEX_UNLOCK(dbptr);
			return NULL;
		}
	}
	
	/*
	 *	Schedule a disk write.
	 */	
	dbptr->altered = 1;

	if (!tiptr->set_cb) {
		/*fprintf(stderr, "%s:%s():%i: Warning: Unable to set data at \"%s/%s\" "
			"in database; type %i does not support it.\n",
			__FILE__, __FUNCTION__, __LINE__, path, key, tiptr->bitmask);*/
	} else
		tiptr->set_cb(nptr, data);

	PDB_MUTEX_UNLOCK(dbptr);
	return nptr;
}
Esempio n. 2
0
/*
 *	Return a given node from the database.
 */
DLLEXP struct pdb_node_t* pdb_query_node(struct pdb* dbptr, char* path) {
	char** tok_arr;
	struct pdb_node_t* nptr;
	struct pdb_node_types_t* tiptr;
	int i = 0;
	
	if (!dbptr)
		return 0;

	PDB_MUTEX_LOCK(dbptr);

	if (!strcmp(path, "") || !strcmp(path, "/")) {
		PDB_MUTEX_UNLOCK(dbptr);
		return dbptr->data;
	}
	
	tok_arr = token_parse(path, PDB_PATH_DELIM, NULL);
	
	nptr = dbptr->data;
	tiptr = NULL;
	
	while (tok_arr[i]) {
		tiptr = pdb_get_type_info(nptr->type);
		nptr = tiptr->query_cb(nptr, tok_arr[i]);
		if (!nptr)
			break;
		++i;
	}
	
	token_free(tok_arr);
	
	PDB_MUTEX_UNLOCK(dbptr);

	return nptr;
}
Esempio n. 3
0
/*
 *	Write a given node to disk.
 *
 *	Types without an open_token will have their write callbacks called
 *	without a need line prepended.
 *	Types without a close_token will not have the close_token and new line
 *	appended.
 */
int pdb_standard_write_node(struct pdb* dbptr, FILE* fptr,
	struct pdb_node_t* nptr, int tabs) {

	struct pdb_node_types_t* tiptr;
	int i = 0;
	int ret;
	
	tiptr = pdb_get_type_info(nptr->type);

	if (!tiptr->write_cb) {
		char* trace = pdb_trace(nptr);
		fprintf(stderr, "%s:%s():%i: Warning: Unable to write node \"%s\" to "
			"disk; operation node supported by node type %i.\n",
			__FILE__, __FUNCTION__, __LINE__, trace, nptr->type);
		free(trace);
		return 1;
	}

	/*
	 *	Write tabs -- if any (if tabs != -1 [root]).
	 */
	if (tabs != -1)
		for (; i < tabs; i++)
			fputc('\t', fptr);
	
	/*
	 *	Write key in double quotes followed by an opening token.
	 */
	if (tabs != -1) {
		fputc('\"', fptr);
		if (nptr->id)
			fputs(nptr->id, fptr);
		fputs("\" ", fptr);
		if ((tiptr->write_as_block) && (tiptr->open_token)) {
			fputs(tiptr->open_token, fptr);
			fputc('\n', fptr);
		}
	}
	
	/*
	 *	Write node to disk.
	 */
	ret = tiptr->write_cb(dbptr, fptr, nptr, tabs + 1);
	
	/*
	 *	Write tabs and tree closing token (if tabs != -1 [root]).
	 */
	if ((tabs != -1) && (tiptr->close_token) && (tiptr->write_as_block)) {
		i = 0;
		for (; i < tabs; i++)
			fputc('\t', fptr);
		fputs(tiptr->close_token, fptr);
		fputc('\n', fptr);
	}
	
	return ret;	
}
Esempio n. 4
0
/*
 *	Standard node loading function to be used for
 *	node load callbacks if desired.
 */
int pdb_standard_load_node(FILE* fptr, struct pdb_node_t* pptr,
	char** tok_arr, int* line) {
	
	int type = pptr->type;
	struct pdb_node_types_t* ctiptr = NULL;
	void* cptr = NULL;
	char* tok = pdb_get_token(fptr, &type, line);

	while (tok) {
		/*
		 *	Is the block over?
		 */
		if ((type & BLOCK_CLOSE) == BLOCK_CLOSE) {
			free(tok);
			return 1;
		}
		
		tok_arr = pdb_token_parse(tok);

		/*
		 *	Create the child node and add to parent.
		 */
		ctiptr = pdb_get_type_info(type);
		if (!ctiptr) {
			fprintf(stderr, "%s:%s():%i: Error: Unknown child type %i on line "
				"%i; halting database load.\n", __FILE__, __FUNCTION__,
				__LINE__, type, *line);
			free(tok);
			return 0;
		}
		cptr = ctiptr->create_cb(tok_arr[0], pptr, tok_arr);
		
		/*
		 *	Load the child node (if supported).
		 */
		if (ctiptr->load_cb) {
			if (!ctiptr->load_cb(fptr, cptr, tok_arr, line)) {
				fprintf(stderr, "%s:%s():%i: Error: An error occured while "
					"loading the database; halting database load on line %i.\n",
					__FILE__, __FUNCTION__, __LINE__, *line);
				token_free(tok_arr);
				free(tok);
				return 0;
			}
		}
		
		/*
		 *	Get next token.
		 */
		token_free(tok_arr);
		free(tok);
		type = pptr->type;
		tok = pdb_get_token(fptr, &type, line);
	}
	
	return 1;
}
Esempio n. 5
0
/*
 *	Load a file and return a database pointer.
 *	If file is NULL, create an empty database.
 */
DLLEXP struct pdb* pdb_load(char* file) {
	struct pdb* dbptr;
	struct pdb_node_types_t* rntptr;
	int line = 1;
	FILE* fptr = NULL;
	
	dbptr = (struct pdb*)malloc(sizeof(struct pdb));
	if (!dbptr)
		return NULL;
	
	if (file) {
		fptr = pdb_open_file(file);
		if (!fptr)
			return NULL;
	}
	
	/*
	 *	Initialize pdb structure.
	 */
	dbptr->altered = 0;
	dbptr->last_write = time(NULL);
	dbptr->write_interval = PDB_DEFAULT_WRITE_INTERVAL;
	dbptr->settings = PDB_DEFAULT_SETTINGS;
	#ifdef PDB_USING_THREADS
		dbptr->mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
		pthread_mutex_init(dbptr->mutex, NULL);
	#endif
	
	if (file) {
		dbptr->file = (char*)malloc(sizeof(char) * (strlen(file) + 1));
		strcpy(dbptr->file, file);
	} else
		dbptr->file = NULL;
	
	rntptr = pdb_get_type_info(ROOT_NODE_TYPE);
	if (!rntptr) {
		ERROR("Root node type is invalid.");
		free(dbptr->file);
		free(dbptr);
		pdb_close_file(fptr);
		return NULL;
	}		
	dbptr->data = (*rntptr->create_cb)(NULL, NULL, NULL);
	
	/*
	 *	Load database (if file was specified).
	 */
	if (file) {
		pdb_standard_load_node(fptr, dbptr->data, NULL, &line);
		pdb_close_file(fptr);
	}
	
	return dbptr;
}
Esempio n. 6
0
/*
 *	Write an integer node to disk.
 */
int pdb_write_int_node_cb(struct pdb* dbptr, FILE* fptr,
	struct pdb_node_t* nptr, int tabs) {
		
	struct pdb_node_types_t* tiptr;
		
	tiptr = pdb_get_type_info(INT_NODE_TYPE);
	
	fprintf(fptr, "%s%i%s%c\n",
		tiptr->open_token,
		*(int*)nptr->data,
		tiptr->close_token,
		PDB_TOKEN_TERM);		
	
	return 1;
}
Esempio n. 7
0
/*
 *	Standard node creation function to be used for
 *	node creation callbacks if desired.
 *	This will create and set everything but the data pointer.
 *	It will also add the newly created child to the parent structure.
 */
void* pdb_standard_create_node(char* id, struct pdb_node_t* parent, int type) {
	struct pdb_node_t* nptr;
	struct pdb_node_types_t* tiptr;

	nptr = (struct pdb_node_t*)malloc(sizeof(struct pdb_node_t));
	if (!nptr) {
		ERROR("Unable to allocate memory for node structure.");
		return NULL;
	}
	
	nptr->data = NULL;
	nptr->parent = parent;
	nptr->type = type;
	nptr->custom_free_cb = NULL;
	
	if (id) {
		nptr->id = (char*)malloc(sizeof(char) * (strlen(id) + 1));
		strcpy(nptr->id, id);
	} else
		nptr->id = NULL;
	
	/*
	 *	Add child to parent structure.
	 */
	if (parent) {
		tiptr = pdb_get_type_info(parent->type);
		if (!tiptr->add_child_cb) {
			fprintf(stderr, "%s:%s():%i: Error: Unable to add child node to "
				"parent (type %i); not supported by parent.\n",
				__FILE__, __FUNCTION__, __LINE__, parent->type);
			free(nptr->id);
			free(nptr);
			return NULL;
		} else {
			if (!tiptr->add_child_cb(parent, id, nptr)) {
				fprintf(stderr, "%s:%s():%i: Error: Unable to add child node "
					"of type %i to parent node of type %i.\n",
					__FILE__, __FUNCTION__, __LINE__, tiptr->bitmask, type);
				free(nptr->id);
				free(nptr);
				return NULL;
			}
		}
	}

	return nptr;
}
Esempio n. 8
0
/*
 *	Delete a node from its parent, but don't free the node.
 */
void pdb_del_node_from_parent(struct pdb_node_t* nptr) {
	struct pdb_node_types_t* tiptr;

	if (!nptr->parent)
		return;

	tiptr = pdb_get_type_info(nptr->parent->type);
	
	if (!tiptr->del_child_cb) {
		fprintf(stderr, "%s:%s():%i: Error: Cannot remove '%s' from parent; "
			"type %i does not support operation.\n",
			__FILE__, __FUNCTION__, __LINE__, nptr->id, nptr->parent->type);
		return;
	}
	
	tiptr->del_child_cb(nptr->parent, nptr);
}
Esempio n. 9
0
/*
 *	Callback for loading an integer node.
 */
int pdb_load_int_node_cb(FILE* fptr, struct pdb_node_t* pptr, char** tok_arr,
	int* line) {

	struct pdb_node_types_t* tiptr;
	int* i = (int*)pptr->data;

	tiptr = pdb_get_type_info(INT_NODE_TYPE);

	/*
	 *	Read the integer from the file and set it.
	 */
	fscanf(fptr, tiptr->open_token, NULL);
	fscanf(fptr, "%i", i);
	fscanf(fptr, tiptr->close_token, NULL);
	
	return 1;
}
Esempio n. 10
0
/*
 *	Free a given node based on its type and using the corresponding
 *	free callback function.
 */
int pdb_free_node_cb(void* dptr) {
	struct pdb_node_t* nptr = dptr;
	struct pdb_node_types_t* tiptr;
	int ret = 0;

	if (nptr->custom_free_cb) {
		/*
		 *	Use the custom free callback rather than the default.
		 */
		ret = nptr->custom_free_cb(nptr->data);
	} else {
		tiptr = pdb_get_type_info(nptr->type);
		ret = tiptr->free_cb(nptr);
	}
	if (nptr->id)
		free(nptr->id);
	free(nptr);
	return ret;
}
Esempio n. 11
0
/*
 *	Free a node and remove it from the parent.
 *
 *	Use this function and NOT pdb_node_types_t->free_cb()
 *	if you are deleting a single node from the structure
 *	(e.g. pdb_del rather than pdb_unload).
 */
DLLEXP int pdb_free_node(struct pdb_node_t* nptr) {
	struct pdb_node_types_t* tiptr;
	int ret = 0;

	if (!nptr)
		return 0;

	/*
	 *	Only free the container if it is
	 *	not of type LINK_NODE_TYPE.
	 */
	if (nptr->type != LINK_NODE_TYPE) {
		/*
		 *	Free data container.
		 */
		if (nptr->custom_free_cb) {
			/*
			 *	Use the custom free callback rather than the default.
			 */
			ret = nptr->custom_free_cb(nptr);
		} else {
			tiptr = pdb_get_type_info(nptr->type);
			ret = tiptr->free_cb(nptr);
		}
	}
	nptr->data = NULL;
	
	/*
	 *	Remove from parent.
	 */
	pdb_del_node_from_parent(nptr);

	/*
	 *	Free node.
	 */
	if (nptr->id)
		free(nptr->id);
	free(nptr);
	
	return ret;
}
Esempio n. 12
0
/*
 *	Callback for loading a hash node.
 */
int pdb_load_hash_node_cb(FILE* fptr, struct pdb_node_t* pptr, char** tok_arr,
	int* line) {

	char b;
	int i;
	struct pdb_node_types_t* tiptr = pdb_get_type_info(HASH_NODE_TYPE);
		
	/*
	 *	Move to the next non-white character.
	 */
	while (!feof(fptr)) {
		FPEEK(&b, fptr);
		if (!is_whitespace(b))
			break;
		if (b == '\n')
			*line++;
		fgetc(fptr);
	}
	/*
	 *	Skip over the opening token.
	 */
	for (i = 0; i < (signed)strlen(tiptr->open_token); ++i)
		fgetc(fptr);
	
	/*
	 *	Get the size of the hash table.
	 */
	if (!fscanf(fptr, "%i;", &i)) {
		char* e = va(NULL,
			"Unable to load hash from file -- no size (line %i).\n", *line);
		ERROR(e);
		free(e);
		return 0;
	}
	
	pptr->data = (void*)hash_create(i);

	return pdb_standard_load_node(fptr, pptr, tok_arr, line);
}
Esempio n. 13
0
/*
 *	Create a node link from path/key to tnptr.
 *	Node links will be ignored when written to disk.
 */
DLLEXP int pdb_create_link(struct pdb* dbptr, char* path, char* key,
	struct pdb_node_t* tnptr) {
		
	struct pdb_node_t* nptr;
	struct pdb_node_types_t* tiptr;
	int ret;
		
	if (!dbptr)
		return 0;

	nptr = pdb_query_node(dbptr, path);

	if (!nptr)
		return 0;

	tiptr = pdb_get_type_info(LINK_NODE_TYPE);

	PDB_MUTEX_LOCK(dbptr);
	ret = (tiptr->create_cb(key, nptr, (char**)tnptr) ? 1 : 0);
	
	PDB_MUTEX_UNLOCK(dbptr);
	return ret;
}
Esempio n. 14
0
/*
 *	Return the number of children a container has.
 */
DLLEXP int pdb_count_children(struct pdb* dbptr, char* path) {
	struct pdb_node_types_t* tiptr;
	struct pdb_node_t* nptr;
	int ret;
	
	if (!dbptr)
		return 0;

	nptr = pdb_query_node(dbptr, path);

	if (!nptr)
		return 0;
	
	PDB_MUTEX_LOCK(dbptr);

	tiptr = pdb_get_type_info(nptr->type);
	if (!tiptr) {
		/*
		 *	Play it safe -- container not empty.
		 */
		PDB_MUTEX_UNLOCK(dbptr);
		return 0;
	}
	if (!tiptr->count_children_cb) {
		/*
	 	 *	Again, playing it safe.
		 */
		PDB_MUTEX_UNLOCK(dbptr);
		return 0;
	}
	
	ret = tiptr->count_children_cb(nptr);
	
	PDB_MUTEX_UNLOCK(dbptr);
	return ret;	
}