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 { PREF_CURSOR_FORE_COLOR, "255, 255, 255" }, 48 { PREF_CURSOR_BACK_COLOR, " 0, 0, 0" }, 49 50 { PREF_IM_FORE_COLOR, " 0, 0, 0" }, 51 { PREF_IM_BACK_COLOR, "152, 203, 255" }, 52 { PREF_IM_SELECT_COLOR, "255, 152, 152" }, 53 54 { PREF_SHELL, "/bin/sh -login" }, 55 { PREF_HISTORY_SIZE, "10000" }, 56 57 { PREF_TEXT_ENCODING, "UTF-8" }, 58 59 { PREF_GUI_LANGUAGE, "English"}, 60 { PREF_IM_AWARE, "0"}, 61 { NULL, NULL}, 62 }; 63 64 65 PrefHandler *PrefHandler::sPrefHandler = NULL; 66 67 68 PrefHandler::PrefHandler() 69 : 70 fContainer('Pref') 71 { 72 _LoadFromDefault(kTermDefaults); 73 74 BPath path; 75 GetDefaultPath(path); 76 OpenText(path.Path()); 77 78 _ConfirmFont(PREF_HALF_FONT_FAMILY, be_fixed_font); 79 } 80 81 82 PrefHandler::PrefHandler(const PrefHandler* p) 83 { 84 fContainer = p->fContainer; 85 } 86 87 88 PrefHandler::~PrefHandler() 89 { 90 } 91 92 93 /* static */ 94 PrefHandler * 95 PrefHandler::Default() 96 { 97 if (sPrefHandler == NULL) 98 sPrefHandler = new PrefHandler(); 99 return sPrefHandler; 100 } 101 102 103 /* static */ 104 void 105 PrefHandler::DeleteDefault() 106 { 107 delete sPrefHandler; 108 sPrefHandler = NULL; 109 } 110 111 112 /* static */ 113 void 114 PrefHandler::SetDefault(PrefHandler *prefHandler) 115 { 116 DeleteDefault(); 117 sPrefHandler = prefHandler; 118 } 119 120 121 /* static */ 122 status_t 123 PrefHandler::GetDefaultPath(BPath& path) 124 { 125 status_t status; 126 status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 127 if (status != B_OK) 128 return status; 129 130 status = path.Append("Terminal"); 131 if (status != B_OK) 132 return status; 133 134 // Just create the directory. Harmless if already there 135 status = create_directory(path.Path(), 0755); 136 if (status != B_OK) 137 return status; 138 139 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 140 status = path.Append("Default"); 141 #else 142 status = path.Append("HaikuTerminal_settings"); 143 #endif 144 145 return status; 146 } 147 148 149 status_t 150 PrefHandler::Open(const char *path) 151 { 152 return _LoadFromFile(path); 153 } 154 155 156 status_t 157 PrefHandler::OpenText(const char *path) 158 { 159 return _LoadFromTextFile(path); 160 } 161 162 163 status_t 164 PrefHandler::Save(const char *path) 165 { 166 // make sure the target path exists 167 #if 0 168 // TODO: currently not needed as we're reusing the standard directory 169 BPath directoryPath(path); 170 if (directoryPath.GetParent(&directoryPath) == B_OK) 171 create_directory(directoryPath.Path(), 0755); 172 #endif 173 174 BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 175 return fContainer.Flatten(&file); 176 } 177 178 179 void 180 PrefHandler::SaveDefaultAsText() 181 { 182 BPath path; 183 if (GetDefaultPath(path) == B_OK) 184 SaveAsText(path.Path(), PREFFILE_MIMETYPE); 185 } 186 187 188 void 189 PrefHandler::SaveAsText(const char *path, const char *mimetype, 190 const char *signature) 191 { 192 // make sure the target path exists 193 #if 0 194 BPath directoryPath(path); 195 if (directoryPath.GetParent(&directoryPath) == B_OK) 196 create_directory(directoryPath.Path(), 0755); 197 #endif 198 199 BFile file(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 200 char buffer[512]; 201 type_code type; 202 const char *key; 203 204 for (int32 i = 0; 205 #ifdef B_BEOS_VERSION_DANO 206 fContainer.GetInfo(B_STRING_TYPE, i, &key, &type) == B_OK; 207 #else 208 fContainer.GetInfo(B_STRING_TYPE, i, (char**)&key, &type) == B_OK; 209 #endif 210 i++) { 211 int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n", key, getString(key)); 212 file.Write(buffer, len); 213 } 214 215 if (mimetype != NULL){ 216 BNodeInfo info(&file); 217 info.SetType(mimetype); 218 info.SetPreferredApp(signature); 219 } 220 } 221 222 223 int32 224 PrefHandler::getInt32(const char *key) 225 { 226 const char *value = fContainer.FindString(key); 227 if (value == NULL) 228 return 0; 229 230 return atoi(value); 231 } 232 233 234 float 235 PrefHandler::getFloat(const char *key) 236 { 237 const char *value = fContainer.FindString(key); 238 if (value == NULL) 239 return 0; 240 241 return atof(value); 242 } 243 244 #undef B_TRANSLATE_CONTEXT 245 #define B_TRANSLATE_CONTEXT "Terminal getString" 246 247 const char* 248 PrefHandler::getString(const char *key) 249 { 250 const char *buffer; 251 if (fContainer.FindString(key, &buffer) != B_OK) 252 buffer = B_TRANSLATE("Error!"); 253 254 //printf("%x GET %s: %s\n", this, key, buf); 255 return buffer; 256 } 257 258 259 bool 260 PrefHandler::getBool(const char *key) 261 { 262 const char *value = fContainer.FindString(key); 263 if (value == NULL) 264 return false; 265 266 return !strcmp(value, PREF_TRUE); 267 } 268 269 270 #undef B_TRANSLATE_CONTEXT 271 #define B_TRANSLATE_CONTEXT "Terminal getRGB" 272 273 /** Returns RGB data from given key. */ 274 275 rgb_color 276 PrefHandler::getRGB(const char *key) 277 { 278 rgb_color col; 279 int r, g, b; 280 281 if (const char *s = fContainer.FindString(key)) { 282 sscanf(s, "%d, %d, %d", &r, &g, &b); 283 } else { 284 fprintf(stderr, 285 B_TRANSLATE("PrefHandler::getRGB(%s) - key not found\n"), key); 286 r = g = b = 0; 287 } 288 289 col.red = r; 290 col.green = g; 291 col.blue = b; 292 col.alpha = 255; 293 return col; 294 } 295 296 297 /** Setting Int32 data with key. */ 298 299 void 300 PrefHandler::setInt32(const char *key, int32 data) 301 { 302 char buffer[32]; 303 snprintf(buffer, sizeof(buffer), "%d", (int)data); 304 setString(key, buffer); 305 } 306 307 308 /** Setting Float data with key */ 309 310 void 311 PrefHandler::setFloat(const char *key, float data) 312 { 313 char buffer[32]; 314 snprintf(buffer, sizeof(buffer), "%g", data); 315 setString(key, buffer); 316 } 317 318 319 /** Setting Bool data with key */ 320 321 void 322 PrefHandler::setBool(const char *key, bool data) 323 { 324 if (data) 325 setString(key, PREF_TRUE); 326 else 327 setString(key, PREF_FALSE); 328 } 329 330 331 /** Setting CString data with key */ 332 333 void 334 PrefHandler::setString(const char *key, const char *data) 335 { 336 //printf("%x SET %s: %s\n", this, key, data); 337 fContainer.RemoveName(key); 338 fContainer.AddString(key, data); 339 } 340 341 342 /** Setting RGB data with key */ 343 344 void 345 PrefHandler::setRGB(const char *key, const rgb_color data) 346 { 347 char buffer[32]; 348 snprintf(buffer, sizeof(buffer), "%d, %d, %d", data.red, data.green, data.blue); 349 setString(key, buffer); 350 } 351 352 353 /** Check any peference stored or not. */ 354 355 bool 356 PrefHandler::IsEmpty() const 357 { 358 return fContainer.IsEmpty(); 359 } 360 361 362 void 363 PrefHandler::_ConfirmFont(const char *key, const BFont *fallback) 364 { 365 int32 count = count_font_families(); 366 const char *font = getString(key); 367 if (font == NULL) 368 count = 0; 369 370 font_family family; 371 372 for (int32 i = 0; i < count; i++) { 373 if (get_font_family(i, &family) != B_OK) 374 continue; 375 376 if (!strcmp(family, font)) { 377 // found font family: we can safely use this font 378 return; 379 } 380 } 381 382 // use fall-back font 383 384 fallback->GetFamilyAndStyle(&family, NULL); 385 setString(key, family); 386 } 387 388 389 status_t 390 PrefHandler::_LoadFromFile(const char* path) 391 { 392 // Future: It would be nice if we could simply use a flatened BMessage to 393 // save the settings. (Who cares about compatibility in this case anyway?) 394 395 BFile file(path, B_READ_ONLY); 396 status_t status = file.InitCheck(); 397 if (status != B_OK) 398 return status; 399 400 //fContainer.MakeEmpty(); 401 //fContainer.Unflatten(&file); 402 403 off_t size; 404 if (file.GetSize(&size) != B_OK || size != sizeof(struct termprefs)) 405 return B_ERROR; 406 407 struct termprefs prefs; 408 file.Read(&prefs, size); 409 if (prefs.magic != TP_MAGIC || prefs.version != TP_VERSION) 410 return B_ERROR; 411 412 // Valid settings file! 413 414 setInt32(PREF_COLS, prefs.cols); 415 setInt32(PREF_ROWS, prefs.rows); 416 setInt32(PREF_HALF_FONT_SIZE, prefs.font_size); 417 char *font_family = strtok(prefs.font, "/"); 418 char *font_style = strtok(NULL, ""); 419 setString(PREF_HALF_FONT_FAMILY, font_family); 420 setString(PREF_HALF_FONT_STYLE, font_style); 421 setRGB(PREF_TEXT_BACK_COLOR, prefs.bg); 422 setRGB(PREF_TEXT_FORE_COLOR, prefs.fg); 423 setRGB(PREF_CURSOR_BACK_COLOR, prefs.curbg); 424 setRGB(PREF_CURSOR_FORE_COLOR, prefs.curfg); 425 setRGB(PREF_SELECT_BACK_COLOR, prefs.selbg); 426 setRGB(PREF_SELECT_FORE_COLOR, prefs.selfg); 427 setString(PREF_TEXT_ENCODING, EncodingAsString(prefs.encoding)); 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