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