1 /* 2 * Copyright 2003-2007, Haiku, Inc. All Rights Reserved. 3 * Copyright (c) 2004 Daniel Furrer <assimil8or@users.sourceforge.net> 4 * Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net> 5 * Copyright (c) 1998,99 Kazuho Okui and Takashi Murai. 6 * 7 * Distributed unter the terms of the MIT License. 8 */ 9 10 11 #include "Encoding.h" 12 #include "PrefHandler.h" 13 #include "TermConst.h" 14 15 #include <Catalog.h> 16 #include <Directory.h> 17 #include <Entry.h> 18 #include <File.h> 19 #include <FindDirectory.h> 20 #include <Font.h> 21 #include <GraphicsDefs.h> 22 #include <Locale.h> 23 #include <Message.h> 24 #include <NodeInfo.h> 25 #include <Path.h> 26 27 #include <stdio.h> 28 #include <unistd.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 /* 33 * Startup preference settings. 34 */ 35 static const pref_defaults kTermDefaults[] = { 36 { PREF_COLS, "80" }, 37 { PREF_ROWS, "25" }, 38 39 { PREF_HALF_FONT_FAMILY, "Courier10 BT" }, 40 { PREF_HALF_FONT_STYLE, "Regular" }, 41 { PREF_HALF_FONT_SIZE, "12" }, 42 43 { PREF_TEXT_FORE_COLOR, " 0, 0, 0" }, 44 { PREF_TEXT_BACK_COLOR, "255, 255, 255" }, 45 { PREF_SELECT_FORE_COLOR, "255, 255, 255" }, 46 { PREF_SELECT_BACK_COLOR, " 0, 0, 0" }, 47 48 { PREF_IM_FORE_COLOR, " 0, 0, 0" }, 49 { PREF_IM_BACK_COLOR, "152, 203, 255" }, 50 { PREF_IM_SELECT_COLOR, "255, 152, 152" }, 51 52 { PREF_SHELL, "/bin/sh -login" }, 53 { PREF_HISTORY_SIZE, "10000" }, 54 55 { PREF_TEXT_ENCODING, "UTF-8" }, 56 57 { PREF_GUI_LANGUAGE, "English"}, 58 { PREF_IM_AWARE, "0"}, 59 60 { PREF_WARN_ON_EXIT, PREF_TRUE }, 61 62 { NULL, NULL}, 63 }; 64 65 66 PrefHandler *PrefHandler::sPrefHandler = NULL; 67 68 69 PrefHandler::PrefHandler() 70 : 71 fContainer('Pref') 72 { 73 _LoadFromDefault(kTermDefaults); 74 75 BPath path; 76 GetDefaultPath(path); 77 OpenText(path.Path()); 78 79 _ConfirmFont(PREF_HALF_FONT_FAMILY, be_fixed_font); 80 } 81 82 83 PrefHandler::PrefHandler(const PrefHandler* p) 84 { 85 fContainer = p->fContainer; 86 } 87 88 89 PrefHandler::~PrefHandler() 90 { 91 } 92 93 94 /* static */ 95 PrefHandler * 96 PrefHandler::Default() 97 { 98 if (sPrefHandler == NULL) 99 sPrefHandler = new PrefHandler(); 100 return sPrefHandler; 101 } 102 103 104 /* static */ 105 void 106 PrefHandler::DeleteDefault() 107 { 108 delete sPrefHandler; 109 sPrefHandler = NULL; 110 } 111 112 113 /* static */ 114 void 115 PrefHandler::SetDefault(PrefHandler *prefHandler) 116 { 117 DeleteDefault(); 118 sPrefHandler = prefHandler; 119 } 120 121 122 /* static */ 123 status_t 124 PrefHandler::GetDefaultPath(BPath& path) 125 { 126 status_t status; 127 status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 128 if (status != B_OK) 129 return status; 130 131 status = path.Append("Terminal"); 132 if (status != B_OK) 133 return status; 134 135 // Just create the directory. Harmless if already there 136 status = create_directory(path.Path(), 0755); 137 if (status != B_OK) 138 return status; 139 140 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 141 status = path.Append("Default"); 142 #else 143 status = path.Append("HaikuTerminal_settings"); 144 #endif 145 146 return status; 147 } 148 149 150 status_t 151 PrefHandler::Open(const char *path) 152 { 153 return _LoadFromFile(path); 154 } 155 156 157 status_t 158 PrefHandler::OpenText(const char *path) 159 { 160 return _LoadFromTextFile(path); 161 } 162 163 164 status_t 165 PrefHandler::Save(const char *path) 166 { 167 // make sure the target path exists 168 #if 0 169 // TODO: currently not needed as we're reusing the standard directory 170 BPath directoryPath(path); 171 if (directoryPath.GetParent(&directoryPath) == B_OK) 172 create_directory(directoryPath.Path(), 0755); 173 #endif 174 175 BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 176 return fContainer.Flatten(&file); 177 } 178 179 180 void 181 PrefHandler::SaveDefaultAsText() 182 { 183 BPath path; 184 if (GetDefaultPath(path) == B_OK) 185 SaveAsText(path.Path(), PREFFILE_MIMETYPE); 186 } 187 188 189 void 190 PrefHandler::SaveAsText(const char *path, const char *mimetype, 191 const char *signature) 192 { 193 // make sure the target path exists 194 #if 0 195 BPath directoryPath(path); 196 if (directoryPath.GetParent(&directoryPath) == B_OK) 197 create_directory(directoryPath.Path(), 0755); 198 #endif 199 200 BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 201 char buffer[512]; 202 type_code type; 203 const char *key; 204 205 for (int32 i = 0; 206 #ifdef B_BEOS_VERSION_DANO 207 fContainer.GetInfo(B_STRING_TYPE, i, &key, &type) == B_OK; 208 #else 209 fContainer.GetInfo(B_STRING_TYPE, i, (char**)&key, &type) == B_OK; 210 #endif 211 i++) { 212 int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n", key, getString(key)); 213 file.Write(buffer, len); 214 } 215 216 if (mimetype != NULL){ 217 BNodeInfo info(&file); 218 info.SetType(mimetype); 219 info.SetPreferredApp(signature); 220 } 221 } 222 223 224 int32 225 PrefHandler::getInt32(const char *key) 226 { 227 const char *value = fContainer.FindString(key); 228 if (value == NULL) 229 return 0; 230 231 return atoi(value); 232 } 233 234 235 float 236 PrefHandler::getFloat(const char *key) 237 { 238 const char *value = fContainer.FindString(key); 239 if (value == NULL) 240 return 0; 241 242 return atof(value); 243 } 244 245 #undef B_TRANSLATE_CONTEXT 246 #define B_TRANSLATE_CONTEXT "Terminal getString" 247 248 const char* 249 PrefHandler::getString(const char *key) 250 { 251 const char *buffer; 252 if (fContainer.FindString(key, &buffer) != B_OK) 253 buffer = B_TRANSLATE("Error!"); 254 255 //printf("%x GET %s: %s\n", this, key, buf); 256 return buffer; 257 } 258 259 260 bool 261 PrefHandler::getBool(const char *key) 262 { 263 const char *value = fContainer.FindString(key); 264 if (value == NULL) 265 return false; 266 267 return !strcmp(value, PREF_TRUE); 268 } 269 270 271 #undef B_TRANSLATE_CONTEXT 272 #define B_TRANSLATE_CONTEXT "Terminal getRGB" 273 274 /** Returns RGB data from given key. */ 275 276 rgb_color 277 PrefHandler::getRGB(const char *key) 278 { 279 rgb_color col; 280 int r, g, b; 281 282 if (const char *s = fContainer.FindString(key)) { 283 sscanf(s, "%d, %d, %d", &r, &g, &b); 284 } else { 285 fprintf(stderr, 286 B_TRANSLATE("PrefHandler::getRGB(%s) - key not found\n"), key); 287 r = g = b = 0; 288 } 289 290 col.red = r; 291 col.green = g; 292 col.blue = b; 293 col.alpha = 255; 294 return col; 295 } 296 297 298 /** Setting Int32 data with key. */ 299 300 void 301 PrefHandler::setInt32(const char *key, int32 data) 302 { 303 char buffer[32]; 304 snprintf(buffer, sizeof(buffer), "%d", (int)data); 305 setString(key, buffer); 306 } 307 308 309 /** Setting Float data with key */ 310 311 void 312 PrefHandler::setFloat(const char *key, float data) 313 { 314 char buffer[32]; 315 snprintf(buffer, sizeof(buffer), "%g", data); 316 setString(key, buffer); 317 } 318 319 320 /** Setting Bool data with key */ 321 322 void 323 PrefHandler::setBool(const char *key, bool data) 324 { 325 if (data) 326 setString(key, PREF_TRUE); 327 else 328 setString(key, PREF_FALSE); 329 } 330 331 332 /** Setting CString data with key */ 333 334 void 335 PrefHandler::setString(const char *key, const char *data) 336 { 337 //printf("%x SET %s: %s\n", this, key, data); 338 fContainer.RemoveName(key); 339 fContainer.AddString(key, data); 340 } 341 342 343 /** Setting RGB data with key */ 344 345 void 346 PrefHandler::setRGB(const char *key, const rgb_color data) 347 { 348 char buffer[32]; 349 snprintf(buffer, sizeof(buffer), "%d, %d, %d", data.red, data.green, data.blue); 350 setString(key, buffer); 351 } 352 353 354 /** Check any peference stored or not. */ 355 356 bool 357 PrefHandler::IsEmpty() const 358 { 359 return fContainer.IsEmpty(); 360 } 361 362 363 void 364 PrefHandler::_ConfirmFont(const char *key, const BFont *fallback) 365 { 366 int32 count = count_font_families(); 367 const char *font = getString(key); 368 if (font == NULL) 369 count = 0; 370 371 font_family family; 372 373 for (int32 i = 0; i < count; i++) { 374 if (get_font_family(i, &family) != B_OK) 375 continue; 376 377 if (!strcmp(family, font)) { 378 // found font family: we can safely use this font 379 return; 380 } 381 } 382 383 // use fall-back font 384 385 fallback->GetFamilyAndStyle(&family, NULL); 386 setString(key, family); 387 } 388 389 390 status_t 391 PrefHandler::_LoadFromFile(const char* path) 392 { 393 // Future: It would be nice if we could simply use a flatened BMessage to 394 // save the settings. (Who cares about compatibility in this case anyway?) 395 396 BFile file(path, B_READ_ONLY); 397 status_t status = file.InitCheck(); 398 if (status != B_OK) 399 return status; 400 401 //fContainer.MakeEmpty(); 402 //fContainer.Unflatten(&file); 403 404 off_t size; 405 if (file.GetSize(&size) != B_OK || size != sizeof(struct termprefs)) 406 return B_ERROR; 407 408 struct termprefs prefs; 409 file.Read(&prefs, size); 410 if (prefs.magic != TP_MAGIC || prefs.version != TP_VERSION) 411 return B_ERROR; 412 413 // Valid settings file! 414 415 setInt32(PREF_COLS, prefs.cols); 416 setInt32(PREF_ROWS, prefs.rows); 417 setInt32(PREF_HALF_FONT_SIZE, prefs.font_size); 418 char *font_family = strtok(prefs.font, "/"); 419 char *font_style = strtok(NULL, ""); 420 setString(PREF_HALF_FONT_FAMILY, font_family); 421 setString(PREF_HALF_FONT_STYLE, font_style); 422 setRGB(PREF_TEXT_BACK_COLOR, prefs.bg); 423 setRGB(PREF_TEXT_FORE_COLOR, prefs.fg); 424 setRGB(PREF_SELECT_BACK_COLOR, prefs.selbg); 425 setRGB(PREF_SELECT_FORE_COLOR, prefs.selfg); 426 setString(PREF_TEXT_ENCODING, EncodingAsString(prefs.encoding)); 427 setBool(PREF_WARN_ON_EXIT, prefs.warn_on_exit); 428 429 return B_OK; 430 } 431 432 433 status_t 434 PrefHandler::_LoadFromDefault(const pref_defaults* defaults) 435 { 436 if (defaults == NULL) 437 return B_ERROR; 438 439 while (defaults->key) { 440 setString(defaults->key, defaults->item); 441 ++defaults; 442 } 443 444 return B_OK; 445 } 446 447 448 /** Text is "key","Content" 449 * Comment : Start with '#' 450 */ 451 452 status_t 453 PrefHandler::_LoadFromTextFile(const char * path) 454 { 455 char buffer[1024]; 456 char key[B_FIELD_NAME_LENGTH], data[512]; 457 int n; 458 FILE *file; 459 460 file = fopen(path, "r"); 461 if (file == NULL) 462 return B_ENTRY_NOT_FOUND; 463 464 while (fgets(buffer, sizeof(buffer), file) != NULL) { 465 if (*buffer == '#') 466 continue; 467 468 n = sscanf(buffer, "%*[\"]%[^\"]%*[\"]%*[^\"]%*[\"]%[^\"]", key, data); 469 if (n == 2) 470 setString(key, data); 471 } 472 473 fclose(file); 474 return B_OK; 475 } 476