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