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