2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $TOG: UserPreference.C /main/7 1998/04/17 11:38:58 mgreess $
26 * Copyright (c) 1993 HAL Computer Systems International, Ltd.
27 * All rights reserved. Unpublished -- rights reserved under
28 * the Copyright Laws of the United States. USE OF A COPYRIGHT
29 * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
32 * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE
33 * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. USE,
34 * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE
35 * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS
38 * RESTRICTED RIGHTS LEGEND
39 * Use, duplication, or disclosure by the Government is subject
40 * to the restrictions as set forth in subparagraph (c)(l)(ii)
41 * of the Rights in Technical Data and Computer Software clause
42 * at DFARS 252.227-7013.
44 * HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
51 #define C_UserPreference
66 #if !defined(hpux) && !defined(__linux__) && !defined(CSRG_BASED) && !defined(sun)
69 #include <sys/types.h>
74 PreferenceRecord *PreferenceRecord::g_head;
75 PreferenceRecord *PreferenceRecord::g_tail;
76 int PreferenceRecord::g_update_count = -1;
79 PreferenceRecord::PreferenceRecord (const char *key, const char *value)
80 : f_key (strdup (key)),
81 f_value (strdup (value)),
87 g_tail->f_next = this;
92 PreferenceRecord::~PreferenceRecord()
94 free ((char *) f_key);
95 free ((char *) f_value);
100 PreferenceRecord::set_value (const char *value)
102 free ((char *) f_value);
103 f_value = strdup (value);
108 PreferenceRecord::form_filename()
110 // Form the file name of the preferences.
111 static char filename[256];
112 if (filename[0] == '\0')
114 snprintf (filename, sizeof(filename),
115 "%s/preferences", env().user_path());
117 const char *home = env().home();
119 throw (CASTEXCEPT Exception());
120 const char *lang = env().lang();
122 throw (CASTEXCEPT Exception());
124 snprintf (filename, sizeof(filename),
125 "%s/.dt/dtinfo/%s/preferences", home, lang);
134 revert_from_backup (const char *filename)
137 // Failed, so look for the backup file.
139 snprintf (backup, sizeof(backup), "%s.bak", filename);
140 struct stat file_info;
142 if (stat (backup, &file_info) != -1 &&
143 S_ISREG(file_info.st_mode))
146 ret = link (backup, filename);
147 if(ret == 0) throw (CASTEXCEPT Exception());
153 read_version (FILE *stream)
157 // Make sure the file is valid.
159 ret1 = fread (&V, 1, 1, stream);
160 if(ret1 == 0) throw (CASTEXCEPT Exception());
163 // Nab the version from the file.
165 ret2 = fscanf (stream, "%d", &version);
166 if(ret2 == 0) throw (CASTEXCEPT Exception());
172 read_update_count (FILE *stream)
175 char buffer[256], *p;
178 ret = fgets (buffer, 256, stream);
179 if(ret == NULL) throw (CASTEXCEPT Exception());
181 while (*p != ',' && *p != '\0')
186 sscanf (p, "%d", &update_count);
187 ON_DEBUG (printf ("Update count = %d\n", update_count));
188 return (update_count);
192 PreferenceRecord::read_prefs()
194 // Open it and read in the preferences.
195 const char *filename;
202 filename = form_filename();
204 struct stat file_info;
205 int status = stat (filename, &file_info);
208 // Check for access failure or IO error.
209 if (errno == EACCES || errno == EIO)
210 throw (CASTEXCEPT Exception());
211 // It doesn't exists otherwise.
215 else if (!S_ISREG (file_info.st_mode))
216 throw (CASTEXCEPT Exception());
217 stream = fopen (filename, "r");
218 if (stream == NULL) // Open failed, something is bogus.
219 throw (CASTEXCEPT Exception());
221 int version = read_version (stream); // Snag the version.
222 if (version == 0) // See if file is ok.
225 if (attempt == 2) // give up on 2nd attempt
226 throw (CASTEXCEPT Exception());
228 revert_from_backup (filename);
232 g_update_count = read_update_count (stream);
234 // Read in the preference lines.
235 char key[256], *value;
236 while (fgets (key, 256, stream) != NULL)
239 while (*value != ':' && *value != '\0')
241 if (*value == '\0') // Ignore bogus lines.
244 while (isspace ((unsigned char) *value))
246 int len = strlen(value);
248 ON_DEBUG (printf ("Got Pref: %s = %s\n", key, value));
249 new PreferenceRecord (key, value);
256 PreferenceRecord::write_prefs()
258 assert (g_update_count != -1);
260 const char *filename = form_filename();
261 struct stat file_info;
262 int status = stat (filename, &file_info);
263 // Make sure it's a regular file if it exists.
264 if (status == 0 && !S_ISREG (file_info.st_mode))
265 throw (CASTEXCEPT Exception());
267 // Check the update count to guard against overwrites.
268 // This isn't foolproof, but we can't trust NFS locking
269 // so this will have to do for now. 13:39 15-Sep-93 DJB
271 int update_count = 0;
275 // If the file isn't readable, we won't write the prefs.
276 stream = fopen (filename, "r");
278 throw (CASTEXCEPT Exception());
280 if (read_version (stream) != 0)
281 update_count = read_update_count (stream);
285 if (update_count != g_update_count)
287 bool doit = message_mgr().
288 question_dialog ((char*)"Preferences have changed on disk.\nOverwrite?");
293 // Create a backup file from the current preferences, if any.
298 snprintf (backup, sizeof(backup), "%s.bak", filename);
300 if (rename (filename, backup) == -1)
301 throw (CASTEXCEPT Exception());
303 else // Make sure the parent directory exists.
306 snprintf (dirname, sizeof(dirname), "%s", env().user_path());
307 status = stat (dirname, &file_info);
310 if (mkdir (dirname, 0777) == -1)
311 throw (CASTEXCEPT Exception());
313 else if (!S_ISDIR (file_info.st_mode))
314 throw (CASTEXCEPT Exception());
317 // Open the file and write the preferences.
318 stream = fopen (filename, "w");
321 // Put the backup file back where it came from.
322 if (backup[0] != '\0')
323 rename (backup, filename);
324 throw (CASTEXCEPT Exception());
327 // Write out the preference records.
328 PreferenceRecord *current = g_head;
329 // First line is version and update count.
330 fprintf (stream, "-1.0, %d # AUTOMATICALLY GENERATED - DO NOT EDIT!\n",
332 while (current != NULL)
334 if (*(current->f_value) != '\0' &&
335 fprintf(stream, "%s: %s\n", current->f_key, current->f_value) == EOF)
338 // Remove the file and restore the backup file.
339 if (unlink (filename) == 0 && backup[0] != '\0')
340 rename (backup, filename);
341 throw (CASTEXCEPT Exception());
343 current = current->f_next;
346 // Rewrite first character to indicate file is complete.
347 fseek (stream, 0L, 0);
348 fwrite ("V", 1, 1, stream);
355 PreferenceRecord::lookup (const char *key)
357 if (g_update_count == -1)
365 // This will only happen the first time through.
366 message_mgr().error_dialog ((char*)"Unable to read preferences.");
372 // Scan through the list of preferences looking for the record.
373 PreferenceRecord *current = g_head;
374 while (current != NULL)
376 if (strcmp (key, current->f_key) == 0)
378 current = current->f_next;
381 // Not found, so create a new record.
382 return (new PreferenceRecord (key, ""));
386 UserPreference::UserPreference (const char *key)
387 : f_preference (PreferenceRecord::lookup (key))
392 UserPreference::~UserPreference()