Preferences.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /* Preferences.cpp
  2. *
  3. * Copyright (C) 1996-2013,2015-2018 Paul Boersma
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "Preferences.h"
  19. #include "Collection.h"
  20. Thing_define (Preference, SimpleString) {
  21. int type;
  22. void *value;
  23. int min, max;
  24. conststring32 (*getText) (int value);
  25. int (*getValue) (conststring32 text);
  26. void v_destroy () noexcept
  27. override;
  28. /* Warning: copy methods etc. not implemented. */
  29. };
  30. Thing_implement (Preference, SimpleString, 0);
  31. void structPreference :: v_destroy () noexcept {
  32. Preference_Parent :: v_destroy ();
  33. }
  34. static SortedSetOfStringOf <structPreference> thePreferences;
  35. void Preferences_exit_optimizeByLeaking () { thePreferences. _ownItems = false; }
  36. static void Preferences_add (conststring32 string, int type, void *value, int min, int max,
  37. conststring32 (*getText) (int value), int (*getValue) (conststring32 text))
  38. {
  39. autoPreference me = Thing_new (Preference);
  40. my string = Melder_dup (string);
  41. for (char32 *p = & my string [0]; *p != U'\0'; p ++) if (*p == U'_') *p = U'.';
  42. my type = type;
  43. my value = value;
  44. my min = min;
  45. my max = max;
  46. my getText = getText;
  47. my getValue = getValue;
  48. thePreferences. addItem_move (me.move());
  49. }
  50. void Preferences_addByte (conststring32 string, signed char *value, signed char defaultValue)
  51. { *value = defaultValue; Preferences_add (string, bytewa, value, 0, 0, nullptr, nullptr); }
  52. void Preferences_addInt16 (conststring32 string, int *value, int defaultValue)
  53. { *value = defaultValue; Preferences_add (string, int16wa, value, 0, 0, nullptr, nullptr); }
  54. void Preferences_addInt (conststring32 string, int *value, int defaultValue)
  55. { *value = defaultValue; Preferences_add (string, intwa, value, 0, 0, nullptr, nullptr); }
  56. void Preferences_addInteger (conststring32 string, integer *value, integer defaultValue)
  57. { *value = defaultValue; Preferences_add (string, integerwa, value, 0, 0, nullptr, nullptr); }
  58. void Preferences_addUbyte (conststring32 string, unsigned char *value, unsigned char defaultValue)
  59. { *value = defaultValue; Preferences_add (string, ubytewa, value, 0, 0, nullptr, nullptr); }
  60. void Preferences_addUint (conststring32 string, unsigned int *value, unsigned int defaultValue)
  61. { *value = defaultValue; Preferences_add (string, uintwa, value, 0, 0, nullptr, nullptr); }
  62. void Preferences_addUinteger (conststring32 string, uinteger *value, uinteger defaultValue)
  63. { *value = defaultValue; Preferences_add (string, uintegerwa, value, 0, 0, nullptr, nullptr); }
  64. void Preferences_addBool (conststring32 string, bool *value, bool defaultValue)
  65. { *value = defaultValue; Preferences_add (string, questionwa, value, 0, 0, nullptr, nullptr); }
  66. void Preferences_addDouble (conststring32 string, double *value, double defaultValue)
  67. { *value = defaultValue; Preferences_add (string, doublewa, value, 0, 0, nullptr, nullptr); }
  68. void Preferences_addString (conststring32 string, char32 *value, conststring32 defaultValue)
  69. { str32cpy (value, defaultValue); Preferences_add (string, stringwa, value, 0, 0, nullptr, nullptr); }
  70. void _Preferences_addEnum (conststring32 string, int *value, int min, int max,
  71. conststring32 (*getText) (int value), int (*getValue) (conststring32 text), int defaultValue)
  72. {
  73. { *value = defaultValue; Preferences_add (string, enumwa, value, min, max, getText, getValue); }
  74. }
  75. void Preferences_read (MelderFile file) {
  76. /*
  77. * It is possible (see praat.cpp) that this routine is called
  78. * before any preferences have been registered.
  79. * In that case, do nothing.
  80. */
  81. if (thePreferences.size == 0) return;
  82. try {
  83. autoMelderReadText text = MelderReadText_createFromFile (file);
  84. for (;;) {
  85. const mutablestring32 line = MelderReadText_readLine (text.get());
  86. if (! line)
  87. return; // OK: we have read past the last line
  88. char32 *value = str32str (line, U": ");
  89. if (! value)
  90. return; // OK: we have read past the last key-value pair
  91. *value = U'\0', value += 2;
  92. integer ipref = thePreferences. lookUp (line);
  93. if (ipref == 0) {
  94. /*
  95. Recognize some preference names that went obsolete in February 2013.
  96. */
  97. if (Melder_nequ (line, U"FunctionEditor.", 15))
  98. ipref = thePreferences. lookUp (Melder_cat (U"TimeSoundAnalysisEditor.", line + 15));
  99. }
  100. if (ipref == 0) continue; // skip unrecognized keys
  101. Preference pref = thePreferences.at [ipref];
  102. switch (pref -> type) {
  103. case bytewa: * (signed char *) pref -> value =
  104. (int8) strtol (Melder_peek32to8 (value), nullptr, 10); break;
  105. case int16wa: * (int16 *) pref -> value =
  106. (int16) strtol (Melder_peek32to8 (value), nullptr, 10); break;
  107. case intwa: * (int *) pref -> value =
  108. strtol (Melder_peek32to8 (value), nullptr, 10); break;
  109. case integerwa: * (integer *) pref -> value =
  110. strtol (Melder_peek32to8 (value), nullptr, 10); break;
  111. case ubytewa: * (unsigned char *) pref -> value =
  112. (uint8) strtoul (Melder_peek32to8 (value), nullptr, 10); break;
  113. case uintwa: * (unsigned int *) pref -> value =
  114. strtoul (Melder_peek32to8 (value), nullptr, 10); break;
  115. case uintegerwa: * (uinteger *) pref -> value =
  116. strtoul (Melder_peek32to8 (value), nullptr, 10); break;
  117. case doublewa: * (double *) pref -> value =
  118. Melder_a8tof (Melder_peek32to8 (value)); break;
  119. case stringwa: {
  120. str32ncpy ((char32 *) pref -> value, value, Preferences_STRING_BUFFER_SIZE);
  121. ((char32 *) pref -> value) [Preferences_STRING_BUFFER_SIZE - 1] = U'\0'; break;
  122. }
  123. case enumwa: {
  124. int intValue = pref -> getValue (value);
  125. if (intValue < 0)
  126. intValue = pref -> getValue (U"\t"); // look for the default
  127. * (int *) pref -> value = intValue; break;
  128. }
  129. case questionwa: * (bool *) pref -> value =
  130. str32nequ (value, U"yes", 3) ? true :
  131. str32nequ (value, U"no", 2) ? false :
  132. strtol (Melder_peek32to8 (value), nullptr, 10) != 0; break;
  133. }
  134. }
  135. } catch (MelderError) {
  136. Melder_clearError (); // this is done during start-up, so it should never fail
  137. }
  138. }
  139. void Preferences_write (MelderFile file) {
  140. if (thePreferences.size == 0) return;
  141. static MelderString buffer { };
  142. for (integer ipref = 1; ipref <= thePreferences.size; ipref ++) {
  143. Preference pref = thePreferences.at [ipref];
  144. MelderString_append (& buffer, pref -> string.get(), U": ");
  145. switch (pref -> type) {
  146. case bytewa: MelderString_append (& buffer, (int) (* (signed char *) pref -> value)); break;
  147. case int16wa: MelderString_append (& buffer, (* (int16 *) pref -> value)); break;
  148. case intwa: MelderString_append (& buffer, (* (int *) pref -> value)); break;
  149. case integerwa: MelderString_append (& buffer, (* (integer *) pref -> value)); break;
  150. case ubytewa: MelderString_append (& buffer, (int) (* (unsigned char *) pref -> value)); break;
  151. case uintwa: MelderString_append (& buffer, (* (unsigned int *) pref -> value)); break;
  152. case uintegerwa: MelderString_append (& buffer, (* (uinteger *) pref -> value)); break;
  153. case doublewa: MelderString_append (& buffer, (* (double *) pref -> value)); break;
  154. case stringwa: MelderString_append (& buffer, ((conststring32) pref -> value)); break;
  155. case enumwa: MelderString_append (& buffer, pref -> getText (* (int *) pref -> value)); break;
  156. case questionwa: MelderString_append (& buffer, (* (bool *) pref -> value)); break;
  157. }
  158. MelderString_appendCharacter (& buffer, U'\n');
  159. }
  160. try {
  161. MelderFile_writeText (file, buffer.string, kMelder_textOutputEncoding::ASCII_THEN_UTF16);
  162. } catch (MelderError) {
  163. Melder_clearError ();
  164. }
  165. }
  166. /* End of file Preferences.cpp */