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