Revision 64 (by gdshaw@RISCPKG.ORG, 2007/05/21 05:44:33) Disabled exceptions and enabled optimisation to reduce code size.
// This file is part of the free Filer module for RISC OS.
// Copyright � 2007 Graham Shaw.
// Redistribution and modification are permitted under the terms of the
// GNU General Public License (version 2 or any later version).

#include <cstring>
#include <cstdio>
#include <new>

#include "oslib/os.h"
#include "oslib/osfscontrol.h"

#include "pathname_hash.h"
#include "pathname_table.h"
#include "filer_window.h"

// Rules for ensuring thread safety:
// - the UpCall handler may search the index at any time (therefore _size
//   and the content of _index must be valid at all times).
// - the UpCall handler may assume that the link referred to by _tail is
//   always null.  It may change that link from null to non-null at any
//   time, provided that it first moves _tail to a different null link.

/** Upcall handler entry point.
 * The interface is as described in the PRM.
extern "C" void upcall_entry();

pathname_table::pathname_table(int* pollword):
	// Initialise refresh queue.;

	// Initialise free list.;

	// Activate upcall handler.

	// Deactivate upcall handler.

	// Deallocate nodes in index.
	for (unsigned int i=0;i!=_size;++i)
		delete _index_nodes[i];

	// Deallocate nodes in free list.
	while (
		delete n;

	// Deallocate index.
	delete[] _index_data;
	delete[] _index_nodes;

void pathname_table::reserve(size_type capacity)
	// Each allocation is processed separately in order to avoid
	// a memory leak of one of them fails.
	if (_capacity<capacity)
		// Reallocate index data (without allowing the existing index
		// to become invalid until it is no longer needed).
		int* new_index_data=new(std::nothrow) int[capacity];
		for (unsigned int i=0;i!=_size;++i)
		volatile int* old_index_data=_index_data;
		delete[] old_index_data;

		// Reallocate index node pointers (again, without allowing the
		// existing node pointers to become invalid until they are no
		// longer needed).
		volatile node** new_index_nodes=
			new(std::nothrow) volatile node*[capacity];
		for (unsigned int i=0;i!=_size;++i)
		volatile node** old_index_nodes=_index_nodes;
		delete[] old_index_nodes;

		// Create new nodes.
		while (_capacity<capacity)
			node* n=new(std::nothrow) node;

pathname_table::node* pathname_table::insert(filer_window* w)
	// Ensure there is sufficient capacity for one more node.

	// Parse pathname into filing system, special field and tail.
	char* pathtail=0;
	char* fs_special=0;
	fileswitch_fs_no fs_number=osfscontrol_set_temporary_fs(w->pathname(),

	// Calculate hash of pathname.
	unsigned int hash=pathname_hash(pathtail,strlen(pathtail),

	// Find point at which to insert.
	unsigned int f=pathname_find(this,hash);

	// Select node from free list.

	// Initialise node.

	// Increment _size, after first ensuring that this will not cause
	// the index to become unordered.

	// Make space for new index entry.
	for (unsigned int i=_size-1;i!=f;--i)

	// Create new index entry.

	// Return pointer to node.
	return n;

void pathname_table::erase(node* n)
	// Get location of node in index.
	unsigned int f=n->index;

	// Delete from index.
	// Each entry is modified as follows:
	// - first the link to the current node is broken
	// - next the hash is replaced with the new value
	// - finally the link to the new node is established
	// An index entry may therefore point to no node, or to the correct
	// node for the hash, but never to an incorrect node.
	for (unsigned int i=f+1;i!=_size;++i)

	// Remove last entry from index.
	// The last entry is now an inactive duplicate of the penultimate
	// entry, and can be removed by decrementing the size.

	// Return node to free list.

void pathname_table::refresh()
	if (
		// A chain has been started, so the UpCall handler will not now
		// alter _head until _tail is reset.

		// Make a pointer to the first node in the chain.

		// Reset _head and _tail.  The UpCall handler will not now make
		// any changes to the chain about to be processed.;

		while (p)
			// Keep a pointer to the current node, because the chain
			// pointer is about to move.
			node* n=p;

			// Move the chain pointer forward now, because the link is
			// about to be cleared.

			// Clear the forward link and the refresh pending flag
			// (in that order).  This is done before the filer window
			// is refreshed so that if there is further disc activity
			// it is refreshed again.

			// Refresh the filer window to which the node refers.