Commit ed3cbc13 authored by Robert Ricci's avatar Robert Ricci

Merge in changes from the assign-devel branch. This includes:

Ripping out crope and replacing (almost) all cropes, char*s and
strings with fstring

Beginnings of XML parser support (not built by default yet).

Significant re-org of code.

Should now compile with the latest gcc.

Putting link information in stored solutions.

Support for fixing interfaces.
parent e8e5b666
......@@ -23,7 +23,7 @@ all: assign
include $(TESTBED_SRCDIR)/GNUmakerules
OBJS=parse_top.o parse_ptop.o assign.o pclass.o vclass.o config.o score.o \
parser.o solution.o anneal.o featuredesire.o
parser.o solution.o anneal.o featuredesire.o neighborhood.o fstring.o
LIBS+= -lm
LDFLAGS+= -pipe -O3
CXXFLAGS = -pipe -I/usr/local/include -ftemplate-depth-40
......
This diff is collapsed.
......@@ -37,6 +37,7 @@ using namespace __gnu_cxx;
#include "delay.h"
#include "physical.h"
#include "pclass.h"
#include "fstring.h"
// Some defaults for #defines
#ifndef NO_REVERT
......@@ -73,7 +74,7 @@ extern pclass_types vnode_type_table;
#endif
/* Decides based on the temperature if a new score should be accepted or not */
inline int accept(double change, double temperature);
inline bool accept(double change, double temperature);
/* Find a pnode that can satisfy the give vnode */
tb_pnode *find_pnode(tb_vnode *vn);
......@@ -82,7 +83,7 @@ tb_pnode *find_pnode(tb_vnode *vn);
void anneal(bool scoring_selftest, double scale_neighborhood,
double *initial_temperature, double use_connected_pnode_find);
typedef hash_map<crope,crope> name_name_map;
typedef slist<crope> name_slist;
typedef hash_map<fstring,fstring> name_name_map;
typedef slist<fstring> name_slist;
#endif
......@@ -16,8 +16,8 @@
#include <boost/graph/graphviz.hpp>
#endif
#include <fstream.h>
#include <iostream.h>
#include <fstream>
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <math.h>
......@@ -31,6 +31,8 @@
using namespace boost;
#include <stdio.h>
#include "common.h"
#include "delay.h"
#include "physical.h"
......@@ -41,6 +43,10 @@ using namespace boost;
#include "solution.h"
#include "maps.h"
#include "anneal.h"
#ifdef WITH_XML
#include "parse_ptop_xml.h"
#include "parse_top_xml.h"
#endif
// Here we set up all our graphs. Need to create the graphs
// themselves and then setup the property maps.
......@@ -119,6 +125,11 @@ bool print_summary = false;
// Use the 'connected' find algorithm
double use_connected_pnode_find = 0.0f;
#ifdef WITH_XML
// Use XML for file input
bool xml_input = false;
#endif
// XXX - shouldn't be in this file
double absbest;
......@@ -132,8 +143,7 @@ tb_ptype_map ptypes;
*/
// Return the CPU time (in seconds) used by this process
float used_time()
{
float used_time() {
struct rusage ru;
getrusage(RUSAGE_SELF,&ru);
return ru.ru_utime.tv_sec+ru.ru_utime.tv_usec/1000000.0+
......@@ -141,15 +151,23 @@ float used_time()
}
// Read in the .ptop file
void read_physical_topology(char *filename)
{
void read_physical_topology(char *filename) {
ifstream ptopfile;
ptopfile.open(filename);
if (!ptopfile.is_open()) {
cout << "*** Unable to open ptop file " << filename << endl;
exit(EXIT_FATAL);
}
cout << "Physical Graph: " << parse_ptop(PG,SG,ptopfile) << endl;
#ifdef WITH_XML
if (!xml_input) {
cout << "Physical Graph: " << parse_ptop(PG,SG,ptopfile) << endl;
} else {
cout << "Physical Graph: " << parse_ptop_xml(PG,SG,filename) << endl;
}
#else
cout << "Physical Graph: " << parse_ptop(PG,SG,ptopfile) << endl;
#endif
#ifdef DUMP_GRAPH
{
......@@ -210,8 +228,7 @@ void read_physical_topology(char *filename)
// Calculate the minimum spanning tree for the switches - we only consider one
// potential path between each pair of switches.
void calculate_switch_MST()
{
void calculate_switch_MST() {
cout << "Calculating shortest paths on switch fabric." << endl;
// Set up the weight map for Dijkstra's
......@@ -250,15 +267,23 @@ void calculate_switch_MST()
}
// Read in the .top file
void read_virtual_topology(char *filename)
{
void read_virtual_topology(char *filename) {
ifstream topfile;
topfile.open(filename);
if (!topfile.is_open()) {
cout << "*** Unable to open top file " << filename << endl;
exit(EXIT_FATAL);
}
cout << "Virtual Graph: " << parse_top(VG,topfile) << endl;
#ifdef WITH_XML
if (!xml_input) {
cout << "Virtual Graph: " << parse_top(VG,topfile) << endl;
} else {
cout << "Virtual Graph: " << parse_top_xml(VG,filename) << endl;
}
#else
cout << "Virtual Graph: " << parse_top(VG,topfile) << endl;
#endif
#ifdef DUMP_GRAPH
{
......@@ -310,8 +335,7 @@ void prune_unusable_pclasses() {
pclasses.size() << " remain." << endl;
}
void print_help()
{
void print_help() {
cout << "assign [options] ptopfile topfile [config params]" << endl;
cout << "Options: " << endl;
#ifdef TIME_TERMINATE
......@@ -337,6 +361,9 @@ void print_help()
cout << " -c <float> - Use the 'connected' pnode finding algorithm " <<
"<float>*100% of the time." << endl;
cout << " -n - Don't anneal - just do the prechecks." << endl;
#ifdef WITH_XML
cout << " -x - Use XML top and ptop files (still incomplete)" << endl;
#endif
exit(EXIT_FATAL);
}
......@@ -351,7 +378,7 @@ int type_precheck() {
// First, check the regular types
for (name_count_map::iterator vtype_it=vtypes.begin();
vtype_it != vtypes.end();++vtype_it) {
// Check to see if there were any pnodes of the type at all
tb_ptype_map::iterator ptype_it = ptypes.find(vtype_it->first);
if (ptype_it == ptypes.end()) {
......@@ -380,8 +407,9 @@ int type_precheck() {
// Check the vclasses, too
for (name_list_map::iterator vclass_it = vclasses.begin();
vclass_it != vclasses.end(); ++vclass_it) {
bool found_match = false;
// Make sure we actually use this vclass
name_vclass_map::iterator dit = vclass_map.find(vclass_it->first);
name_vclass_map::iterator dit = vclass_map.find(vclass_it->first);
if (dit == vclass_map.end()) {
cout << "***: Internal error - unable to find vtype " <<
vclass_it->first << endl;
......@@ -393,8 +421,7 @@ int type_precheck() {
}
}
bool found_match = false;
for (vector<crope>::iterator vtype_it = vclass_it->second.begin();
for (vector<fstring>::iterator vtype_it = vclass_it->second.begin();
vtype_it != vclass_it->second.end(); vtype_it++) {
tb_ptype_map::iterator mit = ptypes.find(*vtype_it);
if ((mit != ptypes.end()) && (mit->second->pnode_slots() != 0)) {
......@@ -452,12 +479,12 @@ int mapping_precheck() {
int matched_bw = 0;
// Keep track of desires had how many 'hits', so that we can tell
// if any simply were not matched
map<crope,int> matched_desires;
map<fstring,int> matched_desires;
// Keep track of which link types had how many 'hits', so that we can
// tell which type(s) caused this node to fail
tb_vnode::link_counts_map matched_link_counts;
map<crope,bool> matched_links;
map<fstring,bool> matched_links;
tb_vclass *vclass = v->vclass;
tb_vclass::members_map::iterator mit;
......@@ -467,7 +494,7 @@ int mapping_precheck() {
for (;;) {
// Loop over all types this node can take on, which might be only
// one, if it's not part of a vclass
crope this_type;
fstring this_type;
if (vclass) {
this_type = mit->first;
} else {
......@@ -553,7 +580,7 @@ int mapping_precheck() {
tb_vnode::link_counts_map::iterator vit;
for (vit = v->link_counts.begin(); vit != v->link_counts.end();
vit++) {
crope type = vit->first;
fstring type = vit->first;
int count = vit->second;
if (pnode->link_counts.find(type) !=
pnode->link_counts.end()) {
......@@ -600,7 +627,7 @@ nosuchtype:
tb_vnode::link_counts_map::iterator lit;
for (lit = v->link_counts.begin(); lit != v->link_counts.end();
lit++) {
crope type = lit->first;
fstring type = lit->first;
if (!matched_links[type]) {
cout << " No links of type " << type << " found!" << endl;
} else {
......@@ -615,7 +642,7 @@ nosuchtype:
cout << " Too much bandwidth on emulated links!" << endl;
}
for (map<crope,int>::iterator dit = matched_desires.begin();
for (map<fstring,int>::iterator dit = matched_desires.begin();
dit != matched_desires.end();
dit++) {
if (dit->second == 0) {
......@@ -661,11 +688,13 @@ void status_report(int signal) {
<< endl;
}
int main(int argc,char **argv)
{
// From anneal.cc - the best solution found
extern solution best_solution;
int main(int argc,char **argv) {
int seed = 0;
#ifdef GRAPHVIZ_SUPPORT
crope viz_prefix;
fstring viz_prefix;
#endif
bool scoring_selftest = false;
bool prechecks_only = false;
......@@ -674,7 +703,7 @@ int main(int argc,char **argv)
char ch;
timelimit = 0.0;
timetarget = 0.0;
while ((ch = getopt(argc,argv,"s:v:l:t:rpPTdH:oguc:n")) != -1) {
while ((ch = getopt(argc,argv,"s:v:l:t:rpPTdH:oguc:nx")) != -1) {
switch (ch) {
case 's':
if (sscanf(optarg,"%d",&seed) != 1) {
......@@ -737,6 +766,11 @@ int main(int argc,char **argv)
prechecks_only = true;
cout << "Doing only prechecks, exiting early" << endl;
break;
#ifdef WITH_XML
case 'x':
xml_input = true;
break;
#endif
default:
print_help();
}
......@@ -778,8 +812,10 @@ int main(int argc,char **argv)
action2.sa_handler = status_report;
sigemptyset(&action2.sa_mask);
action2.sa_flags = 0;
#ifdef __FreeBSD__
sigaction(SIGINFO,&action2,NULL);
#endif
// Convert options to the common.h parameters.
parse_options(argv, options, noptions);
#ifdef SCORE_DEBUG
......@@ -835,9 +871,9 @@ int main(int argc,char **argv)
// Output graphviz if necessary
#ifdef GRAPHVIZ_SUPPORT
if (viz_prefix.size() != 0) {
crope vviz = viz_prefix + "_virtual.viz";
crope pviz = viz_prefix + "_physical.viz";
crope sviz = viz_prefix + "_switch.viz";
fstring vviz = viz_prefix + "_virtual.viz";
fstring pviz = viz_prefix + "_physical.viz";
fstring sviz = viz_prefix + "_switch.viz";
ofstream vfile,pfile,sfile;
vfile.open(vviz.c_str());
write_graphviz(vfile,VG,vvertex_writer(),vedge_writer(),graph_writer());
......@@ -885,15 +921,15 @@ int main(int argc,char **argv)
cout << "Violations: " << violated << endl;
cout << vinfo;
print_solution();
print_solution(best_solution);
if (print_summary) {
print_solution_summary();
print_solution_summary(best_solution);
}
#ifdef GRAPHVIZ_SUPPORT
if (viz_prefix.size() != 0) {
crope aviz = viz_prefix + "_solution.viz";
fstring aviz = viz_prefix + "_solution.viz";
ofstream afile;
afile.open(aviz.c_str());
write_graphviz(afile,VG,solution_vertex_writer(),
......
<?xml version = '1.0'?>
<kdevelop>
<general>
<author>Robert P Ricci</author>
<email>ricci@flux.utah.edu</email>
<version>$VERSION$</version>
<projectmanagement>KDevCustomProject</projectmanagement>
<primarylanguage>C++</primarylanguage>
<ignoreparts/>
<projectdirectory>/home/ricci/testbed/assign</projectdirectory>
<absoluteprojectpath>true</absoluteprojectpath>
<description/>
<versioncontrol>kdevcvsservice</versioncontrol>
</general>
<kdevcustomproject>
<run>
<mainprogram>assign</mainprogram>
<directoryradio>executable</directoryradio>
<customdirectory>/</customdirectory>
<programargs/>
<terminal>false</terminal>
<autocompile>true</autocompile>
<envvars/>
</run>
<build>
<buildtool>make</buildtool>
<builddir/>
</build>
<make>
<abortonerror>true</abortonerror>
<numberofjobs>2</numberofjobs>
<prio>0</prio>
<dontact>false</dontact>
<makebin>gmake</makebin>
<defaulttarget/>
<makeoptions/>
<selectedenvironment>default</selectedenvironment>
<environments>
<default/>
</environments>
</make>
</kdevcustomproject>
<kdevdebugger>
<general>
<dbgshell/>
<programargs/>
<gdbpath/>
<configGdbScript/>
<runShellScript/>
<runGdbScript/>
<breakonloadinglibs>true</breakonloadinglibs>
<separatetty>false</separatetty>
<floatingtoolbar>false</floatingtoolbar>
</general>
<display>
<staticmembers>false</staticmembers>
<demanglenames>true</demanglenames>
<outputradix>10</outputradix>
</display>
</kdevdebugger>
<kdevdoctreeview>
<ignoretocs>
<toc>ada</toc>
<toc>ada_bugs_gcc</toc>
<toc>bash</toc>
<toc>bash_bugs</toc>
<toc>clanlib</toc>
<toc>fortran_bugs_gcc</toc>
<toc>gnome1</toc>
<toc>gnustep</toc>
<toc>gtk</toc>
<toc>gtk_bugs</toc>
<toc>haskell</toc>
<toc>haskell_bugs_ghc</toc>
<toc>java_bugs_gcc</toc>
<toc>java_bugs_sun</toc>
<toc>kde2book</toc>
<toc>opengl</toc>
<toc>pascal_bugs_fp</toc>
<toc>php</toc>
<toc>php_bugs</toc>
<toc>perl</toc>
<toc>perl_bugs</toc>
<toc>python</toc>
<toc>python_bugs</toc>
<toc>qt-kdev3</toc>
<toc>ruby</toc>
<toc>ruby_bugs</toc>
<toc>sdl</toc>
<toc>sw</toc>
<toc>w3c-dom-level2-html</toc>
<toc>w3c-svg</toc>
<toc>w3c-uaag10</toc>
<toc>wxwidgets_bugs</toc>
</ignoretocs>
<ignoreqt_xml>
<toc>Guide to the Qt Translation Tools</toc>
<toc>Qt Assistant Manual</toc>
<toc>Qt Designer Manual</toc>
<toc>Qt Reference Documentation</toc>
<toc>qmake User Guide</toc>
</ignoreqt_xml>
<ignoredoxygen>
<toc>KDE Libraries (Doxygen)</toc>
</ignoredoxygen>
</kdevdoctreeview>
<kdevfilecreate>
<filetypes/>
<useglobaltypes>
<type ext="ui" />
<type ext="cpp" />
<type ext="h" />
</useglobaltypes>
</kdevfilecreate>
<cppsupportpart>
<filetemplates>
<interfacesuffix>.h</interfacesuffix>
<implementationsuffix>.cc</implementationsuffix>
</filetemplates>
</cppsupportpart>
<kdevcppsupport>
<codecompletion>
<includeGlobalFunctions>true</includeGlobalFunctions>
<includeTypes>true</includeTypes>
<includeEnums>true</includeEnums>
<includeTypedefs>false</includeTypedefs>
<automaticCodeCompletion>true</automaticCodeCompletion>
<automaticArgumentsHint>true</automaticArgumentsHint>
<automaticHeaderCompletion>true</automaticHeaderCompletion>
<codeCompletionDelay>250</codeCompletionDelay>
<argumentsHintDelay>400</argumentsHintDelay>
<headerCompletionDelay>250</headerCompletionDelay>
</codecompletion>
<creategettersetter>
<prefixGet/>
<prefixSet>set</prefixSet>
<prefixVariable>m_,_</prefixVariable>
<parameterName>theValue</parameterName>
<inlineGet>true</inlineGet>
<inlineSet>true</inlineSet>
</creategettersetter>
<references/>
</kdevcppsupport>
<kdevdocumentation>
<projectdoc>
<docsystem/>
<docurl/>
<usermanualurl/>
</projectdoc>
</kdevdocumentation>
<kdevfileview>
<groups>
<group pattern="*.cc" name="impl files" />
<group pattern="*.h" name="headers" />
<hidenonprojectfiles>false</hidenonprojectfiles>
<hidenonlocation>false</hidenonlocation>
</groups>
<tree>
<hidepatterns>*.o,*.lo,CVS</hidepatterns>
<hidenonprojectfiles>false</hidenonprojectfiles>
<showvcsfields>true</showvcsfields>
</tree>
</kdevfileview>
<ctagspart>
<customArguments/>
<customTagfilePath/>
</ctagspart>
</kdevelop>
# KDevelop Custom Project File List
anneal.cc
anneal.h
assign.cc
common.h
config.c
config.cc
config.h
delay.h
featuredesire.cc
featuredesire.h
maps.h
parse_ptop.cc
parse_top.cc
parser.cc
parser.h
pclass.cc
pclass.h
physical.h
port.h
score.cc
score.h
solution.cc
solution.h
vclass.cc
vclass.h
virtual.h
<?xml version = '1.0' encoding = 'UTF-8'?>
<!DOCTYPE KDevPrjSession>
<KDevPrjSession>
<DocsAndViews NumberOfDocuments="9" >
<Doc0 NumberOfViews="1" URL="file:///gemini/home/ricci/testbed/assign/parse_ptop_xml.h" >
<View0 line="10" Type="Source" />
</Doc0>
<Doc1 NumberOfViews="1" URL="file:///gemini/home/ricci/testbed/assign/parse_ptop_xml.cc" >
<View0 line="211" Type="Source" />
</Doc1>
<Doc2 NumberOfViews="1" URL="file:///gemini/home/ricci/testbed/assign/xmlhelpers.h" >
<View0 line="62" Type="Source" />
</Doc2>
<Doc3 NumberOfViews="1" URL="file:///gemini/home/ricci/testbed/assign/GNUmakefile" >
<View0 line="0" Type="Source" />
</Doc3>
<Doc4 NumberOfViews="1" URL="file:///gemini/home/ricci/testbed/assign/test-ptop.xml" >
<View0 line="0" Type="Source" />
</Doc4>
<Doc5 NumberOfViews="1" URL="file:///gemini/home/ricci/testbed/assign/ptop.dtd" >
<View0 line="0" Type="Source" />
</Doc5>
<Doc6 NumberOfViews="1" URL="file:///gemini/home/ricci/testbed/assign/physical.h" >
<View0 line="0" Type="Source" />
</Doc6>
<Doc7 NumberOfViews="1" URL="file:///gemini/home/ricci/testbed/assign/tags" >
<View0 line="0" Type="Source" />
</Doc7>
<Doc8 NumberOfViews="1" URL="file:///gemini/home/ricci/testbed/assign/assign.cc" >
<View0 line="157" Type="Source" />
</Doc8>
</DocsAndViews>
<pluginList>
<kdevdebugger>
<breakpointList/>
</kdevdebugger>
<kdevbookmarks>
<bookmarks>
<bookmark url="/gemini/home/ricci/testbed/assign/parse_ptop_xml.cc" >
<mark line="108" />
<mark line="233" />
</bookmark>
</bookmarks>
</kdevbookmarks>
<kdevvalgrind>
<executable path="" params="" />
<valgrind path="" params="" />
<calltree path="" params="" />
<kcachegrind path="" />
</kdevvalgrind>
</pluginList>
</KDevPrjSession>
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2003 University of Utah and the Flux Group.
* Copyright (c) 2000-2006 University of Utah and the Flux Group.
* All rights reserved.
*/
......@@ -13,6 +13,7 @@
*/
#if __GNUC__ == 3 && __GNUC_MINOR__ > 0
#include <ext/hash_map>
#include <ext/hash_fun.h>
using namespace __gnu_cxx;
#define RANDOM() random()
#else
......@@ -22,7 +23,8 @@ using namespace __gnu_cxx;
#include "config.h"
#include <utility>
#include <rope>
#include "port.h"
#include "fstring.h"
#include <boost/graph/adjacency_list.hpp>
......@@ -132,8 +134,8 @@ static float SCORE_MAX_TYPES = 0.15; /* Cost of going over type limits - low
* over leaving a node unassigned */
// The following are used to weight possible link resolutions. Higher
// numbers mean a more likely resolution. Trivial resolutions are always
// used if possible.
// numbers mean a more likely resolution.
static float LINK_RESOLVE_TRIVIAL = 8.0;
static float LINK_RESOLVE_DIRECT = 4.0;
static float LINK_RESOLVE_INTRASWITCH = 2.0;
static float LINK_RESOLVE_INTERSWITCH = 1.0;
......@@ -182,6 +184,22 @@ struct eqstr
}
};
#if __GNUC__ == 3 && __GNUC_MINOR__ > 0
namespace __gnu_cxx
{
#endif
template<> struct hash< std::string >
{
size_t operator()( const std::string& x ) const
{
return hash< const char* >()( x.c_str() );
}
};
#if __GNUC__ == 3 && __GNUC_MINOR__ > 0
};
#endif
enum edge_data_t {edge_data};
enum vertex_data_t {vertex_data};
......@@ -193,8 +211,8 @@ namespace boost {
/*
* Used to count the number of nodes in each ptype and vtype
*/
typedef hash_map<crope,int> name_count_map;
typedef hash_map<crope,vector<crope> > name_list_map;
typedef hash_map<fstring,int> name_count_map;
typedef hash_map<fstring,vector<fstring> > name_list_map;
/*
* A hash function for pointers
......
......@@ -9,11 +9,13 @@
// For DBL_MAX
#include <float.h>
// For fabs()
#include <math.h>
#include <iostream>
using namespace std;
template <class T> inline double basic_distance(T a,T b) {
inline double double_distance(double a,double b) {
if (b == 0) {
if (a == 0)
return 0;
......@@ -23,13 +25,13 @@ template <class T> inline double basic_distance(T a,T b) {
return fabs((double)a/(double)b - 1.0);
}
inline double delay_distance(int a, int b) {
return basic_distance(a,b);
return double_distance((double)a,(double)b);
}
inline double bandwidth_distance(int a,int b) {
return basic_distance(a,b);
return double_distance((double)a,(double)b);
}
inline double loss_distance(double a,double b) {
return basic_distance(a,b);
return double_distance(a,b);
}
class tb_delay_info {
......
......@@ -9,6 +9,8 @@
*/
#include "featuredesire.h"
#include <iostream>
using namespace std;
/*********************************************************************
* tb_featuredesire
......@@ -16,11 +18,10 @@
tb_featuredesire::name_featuredesire_map
tb_featuredesire::featuredesires_by_name;
/*
* Constructor
*/
tb_featuredesire::tb_featuredesire(crope _my_name) : my_name(_my_name),
tb_featuredesire::tb_featuredesire(fstring _my_name) : my_name(_my_name),
global(false), local(false),
l_additive(false), g_one_is_okay(false),
g_more_than_one(false),
......@@ -87,7 +88,7 @@ ostream &operator<<(ostream &o, const tb_featuredesire &fd) {
/*
* Static functions
*/
tb_featuredesire *tb_featuredesire::get_featuredesire_obj(const crope name) {
tb_featuredesire *tb_featuredesire::get_featuredesire_obj(const fstring name) {
name_featuredesire_map::iterator it =
featuredesires_by_name.find(name);
if (it == featuredesires_by_name.end()) {
......@@ -118,7 +119,7 @@ void tb_featuredesire::remove_global_user(int howmany) {
/*
* Constructor
*/
tb_node_featuredesire::tb_node_featuredesire(crope _name, double _weight) :
tb_node_featuredesire::tb_node_featuredesire(fstring _name, double _weight) :
weight(_weight), violateable(false), used_local_capacity(0.0f) {
// We'll want to change in the in the future to seperate out the notions of
// score and violations
......
......@@ -9,10 +9,11 @@
#include "common.h"
#include <rope>
#include <map>
#include <set>
#include <slist>
#include "port.h"
#include "fstring.h"
#include <iostream>
using namespace std;
/*
* Base class for features and desires - not intended to be used directly, only
......@@ -31,7 +32,7 @@ class tb_featuredesire {
* Get the object for a particular feature/desire - if one does not
* exist, creates a new one. Otherwise, returns the existing object
*/
static tb_featuredesire *get_featuredesire_obj(const crope name);
static tb_featuredesire *get_featuredesire_obj(const fstring name);
/*
* Silly accessor functions
......@@ -42,7 +43,7 @@ class tb_featuredesire {
inline bool is_g_one() const { return g_one_is_okay; }
inline bool is_g_more() const { return g_more_than_one; }
inline int global_use_count() const { return in_use_globally; }
inline crope name() const { return my_name; }