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