Now you can download a copy of these docs so you can use them offline! Download now
Preferences.cpp
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2011. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
5 /*----------------------------------------------------------------------------*/
6 
7 #include "Preferences.h"
8 
9 #include "NetworkCommunication/UsageReporting.h"
10 #include "Synchronized.h"
11 #include "WPIErrors.h"
12 
13 #include <stdio.h>
14 #include <algorithm>
15 
17 extern "C" int Priv_SetWriteFileAllowed(uint32_t enable);
18 
20 static const char *kTableName = "Preferences";
22 static const char *kSaveField = "~S A V E~";
24 static const char *kFileName = "/c/wpilib-preferences.ini";
26 static const char *kValuePrefix = "=\"";
28 static const char *kValueSuffix = "\"\n";
30 Preferences *Preferences::_instance = NULL;
31 
32 Preferences::Preferences() :
33  m_fileLock(NULL),
34  m_fileOpStarted(NULL),
35  m_tableLock(NULL),
36  m_readTask("PreferencesReadTask", (FUNCPTR)Preferences::InitReadTask),
37  m_writeTask("PreferencesWriteTask", (FUNCPTR)Preferences::InitWriteTask)
38 {
39  m_fileLock = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE);
40  m_fileOpStarted = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
41  m_tableLock = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE);
42 
43  Synchronized sync(m_fileLock);
44  m_readTask.Start((uint32_t)this);
45  semTake(m_fileOpStarted, WAIT_FOREVER);
46 
47  nUsageReporting::report(nUsageReporting::kResourceType_Preferences, 0);
48 }
49 
50 Preferences::~Preferences()
51 {
52  semTake(m_tableLock, WAIT_FOREVER);
53  semDelete(m_tableLock);
54  semTake(m_fileLock, WAIT_FOREVER);
55  semDelete(m_fileOpStarted);
56  semDelete(m_fileLock);
57 }
58 
64 {
65  if (_instance == NULL)
66  _instance = new Preferences;
67  return _instance;
68 }
69 
74 std::vector<std::string> Preferences::GetKeys()
75 {
76  return m_keys;
77 }
78 
86 std::string Preferences::GetString(const char *key, const char *defaultValue)
87 {
88  std::string value = Get(key);
89  return value.empty() ? defaultValue : value;
90 }
91 
101 int Preferences::GetString(const char *key, char *value, int valueSize, const char *defaultValue)
102 {
103  std::string stringValue = GetString(key, defaultValue);
104  stringValue.copy(value, valueSize);
105  return stringValue.size();
106 }
107 
115 int Preferences::GetInt(const char *key, int defaultValue)
116 {
117  std::string value = Get(key);
118  if (value.empty())
119  return defaultValue;
120 
121  return strtol(value.c_str(), NULL, 0);
122 }
123 
131 double Preferences::GetDouble(const char *key, double defaultValue)
132 {
133  std::string value = Get(key);
134  if (value.empty())
135  return defaultValue;
136 
137  return strtod(value.c_str(), NULL);
138 }
139 
147 float Preferences::GetFloat(const char *key, float defaultValue)
148 {
149  std::string value = Get(key);
150  if (value.empty())
151  return defaultValue;
152 
153  return strtod(value.c_str(), NULL);
154 }
155 
163 bool Preferences::GetBoolean(const char *key, bool defaultValue)
164 {
165  std::string value = Get(key);
166  if (value.empty())
167  return defaultValue;
168 
169  if (value.compare("true") == 0)
170  return true;
171  else if (value.compare("false") == 0)
172  return false;
173 
174  wpi_setWPIErrorWithContext(ParameterOutOfRange, "Boolean value does not contain \"true\" or \"false\"");
175  return false;
176 }
177 
185 INT64 Preferences::GetLong(const char *key, INT64 defaultValue)
186 {
187  std::string value = Get(key);
188  if (value.empty())
189  return defaultValue;
190 
191  // Ummm... not available in our VxWorks...
192  //return strtoll(value.c_str(), NULL, 0);
193  INT64 intVal;
194  sscanf(value.c_str(), "%lld", &intVal);
195  return intVal;
196 }
197 
210 void Preferences::PutString(const char *key, const char *value)
211 {
212  if (value == NULL)
213  {
214  wpi_setWPIErrorWithContext(NullParameter, "value");
215  return;
216  }
217  if (std::string(value).find_first_of("\"") != std::string::npos)
218  {
219  wpi_setWPIErrorWithContext(ParameterOutOfRange, "value contains illegal characters");
220  return;
221  }
222  Put(key, value);
223 }
224 
236 void Preferences::PutInt(const char *key, int value)
237 {
238  char buf[32];
239  snprintf(buf, 32, "%d", value);
240  Put(key, buf);
241 }
242 
254 void Preferences::PutDouble(const char *key, double value)
255 {
256  char buf[32];
257  snprintf(buf, 32, "%f", value);
258  Put(key, buf);
259 }
260 
272 void Preferences::PutFloat(const char *key, float value)
273 {
274  char buf[32];
275  snprintf(buf, 32, "%f", value);
276  Put(key, buf);
277 }
278 
290 void Preferences::PutBoolean(const char *key, bool value)
291 {
292  Put(key, value ? "true" : "false");
293 }
294 
306 void Preferences::PutLong(const char *key, INT64 value)
307 {
308  char buf[32];
309  snprintf(buf, 32, "%lld", value);
310  Put(key, buf);
311 }
312 
325 {
326  Synchronized sync(m_fileLock);
327  m_writeTask.Start((uint32_t)this);
328  semTake(m_fileOpStarted, WAIT_FOREVER);
329 }
330 
336 bool Preferences::ContainsKey(const char *key)
337 {
338  return !Get(key).empty();
339 }
340 
345 void Preferences::Remove(const char *key)
346 {
347  m_values.erase(std::string(key));
348  std::vector<std::string>::iterator it = m_keys.begin();
349  for (; it != m_keys.end(); it++)
350  {
351  if (it->compare(key) == 0)
352  {
353  m_keys.erase(it);
354  break;
355  }
356  }
357 }
358 
364 std::string Preferences::Get(const char *key)
365 {
366  Synchronized sync(m_tableLock);
367  if (key == NULL)
368  {
369  wpi_setWPIErrorWithContext(NullParameter, "key");
370  return std::string("");
371  }
372  return m_values[std::string(key)];
373 }
374 
380 void Preferences::Put(const char *key, std::string value)
381 {
382  Synchronized sync(m_tableLock);
383  if (key == NULL)
384  {
385  wpi_setWPIErrorWithContext(NullParameter, "key");
386  return;
387  }
388 
389  if (std::string(key).find_first_of("=\n\r \t\"") != std::string::npos)
390  {
391  wpi_setWPIErrorWithContext(ParameterOutOfRange, "key contains illegal characters");
392  return;
393  }
394 
395  std::pair<StringMap::iterator, bool> ret =
396  m_values.insert(StringMap::value_type(key, value));
397  if (ret.second)
398  m_keys.push_back(key);
399  else
400  ret.first->second = value;
401 
402  NetworkTable::GetTable(kTableName)->PutString(key, value);
403 }
404 
410 void Preferences::ReadTaskRun()
411 {
412  Synchronized sync(m_tableLock);
413  semGive(m_fileOpStarted);
414 
415  std::string comment;
416 
417  FILE *file = NULL;
418  file = fopen(kFileName, "r");
419 
420  if (file != NULL)
421  {
422  std::string buffer;
423  while (true)
424  {
425  char value;
426  do
427  {
428  value = fgetc(file);
429  } while (value == ' ' || value == '\t');
430 
431  if (value == '\n' || value == ';')
432  {
433  if (value == '\n')
434  {
435  comment += "\n";
436  }
437  else
438  {
439  buffer.clear();
440  for (; value != '\n' && !feof(file); value = fgetc(file))
441  buffer += value;
442  buffer += '\n';
443  comment += buffer;
444  }
445  }
446  else if (value == '[')
447  {
448  // Find the end of the section and the new line after it and throw it away
449  for (; value != ']' && !feof(file); value = fgetc(file));
450  for (; value != '\n' && !feof(file); value = fgetc(file));
451  }
452  else
453  {
454  buffer.clear();
455  for (; value != '=' && !feof(file); )
456  {
457  buffer += value;
458  do
459  {
460  value = fgetc(file);
461  } while (value == ' ' || value == '\t');
462  }
463  std::string name = buffer;
464  buffer.clear();
465 
466  bool shouldBreak = false;
467 
468  do
469  {
470  value = fgetc(file);
471  } while (value == ' ' || value == '\t');
472 
473  if (value == '"')
474  {
475  for (value = fgetc(file); value != '"' && !feof(file); value = fgetc(file))
476  buffer += value;
477 
478  // Clear the line
479  while (fgetc(file) != '\n' && !feof(file));
480  }
481  else
482  {
483  for (; value != '\n' && !feof(file);)
484  {
485  buffer += value;
486  do
487  {
488  value = fgetc(file);
489  } while (value == ' ' || value == '\t');
490  }
491  if (feof(file))
492  shouldBreak = true;
493  }
494 
495  std::string value = buffer;
496 
497  if (!name.empty() && !value.empty())
498  {
499  m_keys.push_back(name);
500  m_values.insert(std::pair<std::string, std::string>(name, value));
501  NetworkTable::GetTable(kTableName)->PutString(name, value);
502 
503  if (!comment.empty())
504  {
505  m_comments.insert(std::pair<std::string, std::string>(name, comment));
506  comment.clear();
507  }
508  }
509 
510  if (shouldBreak)
511  break;
512  }
513  }
514  }
515  else
516  {
517  wpi_setWPIErrorWithContext(NoAvailableResources, "Failed to open preferences file.");
518  }
519 
520  if (file != NULL)
521  fclose(file);
522 
523  if (!comment.empty())
524  m_endComment = comment;
525 
526  NetworkTable::GetTable(kTableName)->PutBoolean(kSaveField, false);
527  NetworkTable::GetTable(kTableName)->AddTableListener(this);
528 }
529 
534 void Preferences::WriteTaskRun()
535 {
536  Synchronized sync(m_tableLock);
537  semGive(m_fileOpStarted);
538 
539  FILE *file = NULL;
540  Priv_SetWriteFileAllowed(1);
541  file = fopen(kFileName, "w");
542 
543  fputs("[Preferences]\n", file);
544  std::vector<std::string>::iterator it = m_keys.begin();
545  for (; it != m_keys.end(); it++)
546  {
547  std::string key = *it;
548  std::string value = m_values[key];
549  std::string comment = m_comments[key];
550 
551  if (!comment.empty())
552  fputs(comment.c_str(), file);
553 
554  fputs(key.c_str(), file);
555  fputs(kValuePrefix, file);
556  fputs(value.c_str(), file);
557  fputs(kValueSuffix, file);
558  }
559 
560  if (!m_endComment.empty())
561  fputs(m_endComment.c_str(), file);
562 
563  if (file != NULL)
564  fclose(file);
565 
566  NetworkTable::GetTable(kTableName)->PutBoolean(kSaveField, false);
567 }
568 
569 static bool isKeyAcceptable(const std::string& value) {
570  for (unsigned int i = 0; i < value.length(); i++) {
571  char letter = value.at(i);
572  switch (letter) {
573  case '=':
574  case '\n':
575  case '\r':
576  case ' ':
577  case '\t':
578  return false;
579  }
580  }
581  return true;
582 }
583 void Preferences::ValueChanged(ITable* table, const std::string& key, EntryValue value, bool isNew)
584 {
585  if (key==kSaveField)
586  {
587  if (table->GetBoolean(kSaveField, false))
588  Save();
589  }
590  else
591  {
592  Synchronized sync(m_tableLock);
593 
594  if (!isKeyAcceptable(key) || table->GetString(key, "").find('"')!=std::string::npos)
595  {
596  if(m_values.find(key) != m_values.end()){
597  m_values.erase(key);
598  std::vector<std::string>::iterator it = m_keys.begin();
599  for (; it != m_keys.end(); it++)
600  {
601  if (key==*it)
602  {
603  m_keys.erase(it);
604  break;
605  }
606  }
607  table->PutString(key, "\"");
608  }
609  }
610  else
611  {
612  std::pair<StringMap::iterator, bool> ret =
613  m_values.insert(StringMap::value_type(key, table->GetString(key, "")));
614  if (ret.second)
615  m_keys.push_back(key);
616  else
617  ret.first->second = table->GetString(key, "");
618  }
619  }
620 }
bool Start(uint32_t arg0=0, uint32_t arg1=0, uint32_t arg2=0, uint32_t arg3=0, uint32_t arg4=0, uint32_t arg5=0, uint32_t arg6=0, uint32_t arg7=0, uint32_t arg8=0, uint32_t arg9=0)
Definition: Task.cpp:52
std::vector< std::string > GetKeys()
Definition: Preferences.cpp:74
std::string GetString(const char *key, const char *defaultValue="")
Definition: Preferences.cpp:86
static NetworkTable * GetTable(std::string key)
void ValueChanged(ITable *source, const std::string &key, EntryValue value, bool isNew)
Definition: ITable.h:26
bool GetBoolean(const char *key, bool defaultValue=false)
void PutBoolean(std::string key, bool value)
void PutDouble(const char *key, double value)
void PutBoolean(const char *key, bool value)
void PutFloat(const char *key, float value)
void Remove(const char *key)
void PutString(const char *key, const char *value)
int GetInt(const char *key, int defaultValue=0)
void PutInt(const char *key, int value)
double GetDouble(const char *key, double defaultValue=0.0)
void PutLong(const char *key, INT64 value)
INT64 GetLong(const char *key, INT64 defaultValue=0)
virtual std::string GetString(std::string key)=0
void AddTableListener(ITableListener *listener)
void PutString(std::string key, std::string value)
bool ContainsKey(const char *key)
Definition: ITable.h:13
virtual bool GetBoolean(std::string key)=0
float GetFloat(const char *key, float defaultValue=0.0)
virtual void PutString(std::string key, std::string value)=0
static Preferences * GetInstance()
Definition: Preferences.cpp:63

Generated on Sat Apr 26 2014 12:26:45 for WPILibC++ by doxygen 1.8.6