Pol  Revision:cb584c9
menu.cpp
Go to the documentation of this file.
1 
7 #include "menu.h"
8 
9 #include <cstddef>
10 #include <string>
11 
12 #include "../clib/cfgelem.h"
13 #include "../clib/cfgfile.h"
14 #include "../clib/clib.h"
15 #include "../clib/fileutil.h"
16 #include "../clib/logfacility.h"
17 #include "../clib/passert.h"
18 #include "../clib/rawtypes.h"
19 #include "../clib/stlutil.h"
20 #include "../plib/systemstate.h"
21 #include "globals/uvars.h"
22 #include "item/itemdesc.h"
23 
24 namespace Pol
25 {
26 namespace Core
27 {
28 MenuItem::MenuItem() : objtype_( 0 ), graphic_( 0 ), color_( 0 ), submenu_id( 0 )
29 {
30  title[0] = '\0';
31  submenu_name[0] = '\0';
32 }
33 
34 Menu::Menu() : menu_id( 0 )
35 {
36  weakptr.set( this );
37 
38  name[0] = '\0';
39  title[0] = '\0';
40 }
41 
42 Menu::Menu( const Menu& other ) : menu_id( other.menu_id ), menuitems_( other.menuitems_ )
43 {
44  strzcpy( name, other.name, sizeof name );
45  strzcpy( title, other.title, sizeof title );
46 
47  weakptr.set( this );
48 }
49 Menu& Menu::operator=( const Menu& rhs )
50 {
51  Menu tmpMenu( rhs );
52 
53  std::swap( menu_id, tmpMenu.menu_id );
54  std::swap( name, tmpMenu.name );
55  std::swap( title, tmpMenu.title );
56  std::swap( menuitems_, tmpMenu.menuitems_ );
57 
58  weakptr.set( this );
59 
60  return *this;
61 }
62 
63 size_t Menu::estimateSize() const
64 {
65  size_t size = sizeof( Menu );
66  size += 3 * sizeof( MenuItem* ) + menuitems_.capacity() * sizeof( MenuItem );
67  return size;
68 }
69 
70 /*
71 u16 GetMenuId( void )
72 {
73 static u16 next_menuid =
74 }
75 */
76 
77 // TODO:: rewrite using std::find() and stlutil.h case insensitive string cmp
78 // -- leaving the warning here as a reminder --
79 Menu* Menu::find_menu( const char* name )
80 {
81  for ( unsigned idx = 0; idx < gamestate.menus.size(); idx++ )
82  {
83  Menu* menu = &gamestate.menus[idx];
84  if ( stricmp( menu->name, name ) == 0 )
85  return menu;
86  }
87  return nullptr;
88 }
89 
90 // currently a menu ID is its location in the array.
91 // we assume the code somehow validates menu choices. For example,
92 // this is currently done by remembering which menu we sent a client.
93 // and only allowing the client to use that particular menu.
94 Menu* Menu::find_menu( unsigned short menu_id )
95 {
96  passert( menu_id > 0 && menu_id <= gamestate.menus.size() );
97 
98  return &gamestate.menus[menu_id - 1];
99 }
100 
102 {
103  if ( !Clib::FileExists( "config/menus.cfg" ) )
104  {
105  if ( Plib::systemstate.config.loglevel > 1 )
106  INFO_PRINT << "File config/menus.cfg not found, skipping.\n";
107  return;
108  }
109 
110  Clib::ConfigFile cf( "config/menus.cfg" );
111 
112  Clib::ConfigElem elem;
113 
114  while ( cf.read( elem ) )
115  {
116  std::string menu_name;
117  std::string menu_title;
118  std::string propname;
119  std::string value;
120 
121  if ( stricmp( elem.type(), "ItemMenu" ) != 0 )
122  continue;
123 
124  menu_name = elem.remove_string( "NAME" );
125  menu_title = elem.remove_string( "TITLE" );
126 
127  gamestate.menus.push_back( Menu() );
128  Menu* menu = &gamestate.menus.back();
129 
130  menu->menu_id = static_cast<unsigned short>( gamestate.menus.size() );
131  strzcpy( menu->name, menu_name.c_str(), sizeof menu->name );
132  strzcpy( menu->title, menu_title.c_str(), sizeof menu->title );
133 
134  while ( elem.remove_first_prop( &propname, &value ) )
135  {
136  if ( stricmp( propname.c_str(), "SubMenu" ) == 0 ||
137  stricmp( propname.c_str(), "Entry" ) == 0 )
138  {
139  std::string submenu_name;
140  std::string objtype_str;
141  std::string title;
142 
143  /*
144  char *submenu_name = nullptr;
145  char *objtype_str = nullptr;
146  char *title = nullptr;
147  */
148 
149  if ( stricmp( propname.c_str(), "SubMenu" ) == 0 )
150  {
151  ISTRINGSTREAM is( value );
152  is >> submenu_name >> objtype_str;
153 
154  // skipws
155  // is.eatwhite();
156 
157  std::getline( is, title ); // title.getline( is );
158 
159  // FIXME: remove leading spaces (better way? please? anyone?)
160  while ( isspace( title[0] ) )
161  title.erase( 0, 1 );
162 
163  // char s[100];
164  // is.ignore( std::numeric_limits<int>::max(), ' ' );
165  // is.ignore( std::numeric_limits<int>::max(), '\t' );
166  // is.getline( s, sizeof s );
167  // title = s;
168  /*
169  submenu_name = strtok( value, " \t," );
170  objtype_str = strtok( nullptr, " \t," );
171  title = strtok( nullptr, "" ); // title is the rest of the line
172  while ((title != nullptr) && *title && isspace(*title)) // skip leading spaces
173  title++;
174  */
175  }
176  else // Entry
177  {
178  submenu_name = "";
179  ISTRINGSTREAM is( value );
180  is >> objtype_str; // FIXME objtype_str ends up having the "," on the end
181 
182  std::getline( is, title );
183  // FIXME: remove leading spaces (better way? please? anyone?)
184  while ( isspace( title[0] ) )
185  title.erase( 0, 1 );
186  }
187 
188  if ( objtype_str == "" )
189  {
190  ERROR_PRINT << "Entry in menu " << menu->name
191  << " must provide at least an object type\n";
192  throw std::runtime_error( "Data error in MENUS.CFG" );
193  }
194  u32 objtype = (u32)strtoul( objtype_str.c_str(), nullptr, 0 );
195  if ( objtype == 0 ) // 0 specified, or text
196  {
197  ERROR_PRINT << "Entry in menu " << menu->name << " cannot specify [" << objtype_str
198  << "] as an Object Type.\n";
199  throw std::runtime_error( "Data error in MENUS.CFG" );
200  }
201  if ( ( stricmp( propname.c_str(), "SubMenu" ) == 0 ) && ( submenu_name == "" ) )
202  {
203  ERROR_PRINT << "SubMenu in menu " << menu->name
204  << " needs format: Objtype, Title, SubMenuName [got '" << value << "']\n";
205  throw std::runtime_error( "Data error in MENUS.CFG" );
206  }
207  if ( ( stricmp( propname.c_str(), "Entry" ) == 0 ) && ( submenu_name != "" ) )
208  {
209  ERROR_PRINT << "Entry in menu " << menu->name << " must not specify SubMenuName [got '"
210  << value << "']\n";
211  throw std::runtime_error( "Data error in MENUS.CFG" );
212  }
213 
214  menu->menuitems_.push_back( MenuItem() );
215  MenuItem* mi = &menu->menuitems_.back();
216 
217  mi->objtype_ = objtype;
218  mi->graphic_ = Items::getgraphic( objtype );
219  mi->color_ = Items::getcolor( objtype );
220 
221  if ( title != "" )
222  strzcpy( mi->title, title.c_str(), sizeof mi->title );
223  else
224  mi->title[0] = '\0';
225 
226  if ( submenu_name != "" )
227  strzcpy( mi->submenu_name, submenu_name.c_str(), sizeof mi->submenu_name );
228  else
229  mi->submenu_name[0] = '\0';
230 
231  mi->submenu_id = 0;
232  }
233  else
234  {
235  ERROR_PRINT << "Unexpected property in menu " << menu->name << ": " << propname << "\n";
236  throw std::runtime_error( "Data error in MENUS.CFG" );
237  }
238  }
239  }
240 
241 
242  for ( unsigned menuidx = 0; menuidx < gamestate.menus.size(); menuidx++ )
243  {
244  Menu* menu = &gamestate.menus[menuidx];
245  for ( unsigned itemidx = 0; itemidx < menu->menuitems_.size(); itemidx++ )
246  {
247  MenuItem* mi = &menu->menuitems_[itemidx];
248 
249  if ( mi->submenu_name[0] )
250  {
251  Menu* found = find_menu( mi->submenu_name );
252  if ( found )
253  {
254  mi->submenu_id = found->menu_id;
255  }
256  else
257  {
258  INFO_PRINT << "Unable to find SubMenu " << mi->submenu_name << "\n";
259  }
260  }
261  }
262  }
263 }
264 }
265 }
bool remove_first_prop(std::string *propname, std::string *value)
Definition: cfgfile.cpp:100
std::string remove_string(const char *propname)
Definition: cfgfile.cpp:381
static Menu * find_menu(const char *name)
Definition: menu.cpp:79
SystemState systemstate
Definition: systemstate.cpp:12
unsigned short submenu_id
Definition: menu.h:39
Menu & operator=(const Menu &)
Definition: menu.cpp:49
char title[80]
Definition: menu.h:37
unsigned short getcolor(unsigned int objtype)
Definition: itemdesc.cpp:927
static void read_menus()
Definition: menu.cpp:101
std::vector< MenuItem > menuitems_
Definition: menu.h:57
unsigned short getgraphic(u32 objtype)
Definition: itemdesc.cpp:906
unsigned int u32
Definition: rawtypes.h:27
weak_ptr_owner< Menu > weakptr
Definition: menu.h:67
std::vector< Menu > menus
Definition: uvars.h:154
#define passert(exp)
Definition: passert.h:62
unsigned short menu_id
Definition: menu.h:53
GameState gamestate
Definition: uvars.cpp:74
size_t estimateSize() const
Definition: menu.cpp:63
#define ISTRINGSTREAM
Definition: stlutil.h:73
#define strzcpy
Definition: clib.h:154
#define ERROR_PRINT
Definition: logfacility.h:230
char submenu_name[80]
Definition: menu.h:38
bool FileExists(const char *filename)
Definition: fileutil.cpp:118
bool read(ConfigElem &elem)
Definition: cfgfile.cpp:1015
#define INFO_PRINT
Definition: logfacility.h:223
const char * type() const
Definition: cfgfile.cpp:66
Definition: berror.cpp:12
char name[80]
Definition: menu.h:54
char title[80]
Definition: menu.h:55