Copied in new updated Italian translation from Michele Petrecca. Thanks.
[geda-gaf/peter-b.git] / libgeda / src / f_basic.c
blob8445915417f60e74574d6558c7a20cd69e032e31
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2000 Ales V. Hvezda
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
19 #include <config.h>
21 #include <stdio.h>
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
27 #include <sys/param.h>
28 #include <limits.h>
29 #include <stdlib.h>
30 #include <time.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
34 #include <gtk/gtk.h>
35 #include <libguile.h>
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
40 #include "defines.h"
41 #include "struct.h"
42 #include "globals.h"
44 #include "../include/prototype.h"
46 #ifdef HAVE_LIBDMALLOC
47 #include <dmalloc.h>
48 #endif
50 /*! \brief Opens the schematic file.
51 * \par Function Description
52 * Opens the schematic file. Before it reads the schematic, it tries to
53 * open and read the local gafrc file.
55 * \param [in,out] w_current The TOPLEVEL object to load the schematic into.
56 * \param [in] filename A character string containing the file name
57 * to open.
58 * \return 0 on failure, 1 on success.
60 int f_open(TOPLEVEL *w_current, char *filename)
62 int opened=FALSE;
63 char *full_filename = NULL;
64 char *full_rcfilename = NULL;
65 char *file_directory = NULL;
66 char *saved_cwd = NULL;
67 char *backup_filename = NULL;
68 char load_backup_file = 0;
70 /* has the head been freed yet? */
71 /* probably not hack PAGE */
73 set_window(w_current, w_current->page_current,
74 w_current->init_left, w_current->init_right,
75 w_current->init_top, w_current->init_bottom);
78 /*
79 * If we are only opening a preview window, we don't want to
80 * change the directory. Therefore, if this is only a preview window,
81 * we cache the cwd so we can restore it later.
83 if (w_current->wid == -1) {
84 saved_cwd = getcwd(NULL, 1024);
87 /* get full, absolute path to file */
88 full_filename = f_normalize_filename(filename);
90 /* write full, absolute filename into page_current->page_filename */
91 if (w_current->page_current->page_filename) {
92 g_free(w_current->page_current->page_filename);
94 w_current->page_current->page_filename = g_strdup(full_filename);
96 /* Before we open the page, let's load the corresponding gafrc. */
97 /* First cd into file's directory. */
98 file_directory = g_dirname (full_filename);
100 full_rcfilename = g_strconcat (file_directory,
101 G_DIR_SEPARATOR_S,
102 "gafrc",
103 NULL);
104 if (file_directory) {
105 chdir(file_directory);
106 /* Probably should do some checking of chdir return values */
108 /* If directory is not found, we should do something . . . . */
110 /* Now open RC and process file */
111 g_rc_parse_specified_rc(w_current, full_rcfilename);
113 /* Check if there is a newer autosave backup file */
114 backup_filename = g_strdup_printf("%s%c"AUTOSAVE_BACKUP_FILENAME_STRING,
115 file_directory, G_DIR_SEPARATOR,
116 g_path_get_basename(full_filename));
118 g_free (file_directory);
120 if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) &&
121 (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) {
122 /* An autosave backup file exists. Check if it's newer */
123 struct stat stat_backup;
124 struct stat stat_file;
125 char error_stat = 0;
126 GString *message;
128 if (stat (backup_filename, &stat_backup) != 0) {
129 s_log_message ("f_open: Unable to get stat information of backup file %s.",
130 backup_filename);
131 error_stat = 1 ;
133 if (stat (full_filename, &stat_file) != 0) {
134 s_log_message ("f_open: Unable to get stat information of file %s.",
135 full_filename);
136 error_stat = 1;
138 if ((difftime (stat_file.st_ctime, stat_backup.st_ctime) < 0) ||
139 (error_stat == 1))
141 /* Found an autosave backup. It's newer if error_stat is 0 */
142 message = g_string_new ("");
143 g_string_append_printf(message, "\nWARNING: Found an autosave backup file:\n %s.\n\n", backup_filename);
144 if (error_stat == 1) {
145 g_string_append(message, "I could not guess if it is newer, so you have to"
146 "do it manually.\n");
148 else {
149 g_string_append(message, "The backup copy is newer than the schematic, so it seems you should load it instead of the original file.\n");
151 g_string_append (message, "Gschem usually makes backup copies automatically, and this situation happens when it crashed or it was forced to exit abruptely.\n");
152 if (w_current->page_current->load_newer_backup_func == NULL) {
153 s_log_message(message->str);
154 s_log_message("\nRun gschem and correct the situation.\n\n");
155 fprintf(stderr, message->str);
156 fprintf(stderr, "\nRun gschem and correct the situation.\n\n");
158 else {
159 /* Ask the user if load the backup or the original file */
160 if (w_current->page_current->load_newer_backup_func
161 (w_current, message)) {
162 /* Load the backup file */
163 load_backup_file = 1;
166 g_string_free (message, TRUE);
170 /* Now that we have set the current directory and read
171 * the RC file, it's time to read in the file. */
172 if (load_backup_file == 1) {
173 /* Load the backup file */
174 w_current->page_current->object_tail = (OBJECT *)
175 o_read(w_current, w_current->page_current->object_tail,
176 backup_filename);
178 else {
179 /* Load the original file */
180 w_current->page_current->object_tail = (OBJECT *)
181 o_read(w_current, w_current->page_current->object_tail,
182 full_filename);
185 g_free (backup_filename);
187 if (w_current->page_current->object_tail != NULL) {
188 s_log_message("Opened file [%s]\n", full_filename);
189 opened = TRUE;
191 } else {
192 /* Failed to open page */
193 opened = FALSE;
197 w_current->page_current->object_tail = (OBJECT *)
198 return_tail(w_current->page_current->object_head);
200 /* make sure you init net_consolide to false (default) in all */
201 /* programs */
202 if (w_current->net_consolidate == TRUE) {
203 o_net_consolidate(w_current);
206 if (load_backup_file == 0) {
207 /* If it's not the backup file */
208 w_current->page_current->CHANGED=0; /* added 4/7/98 */
210 else {
211 /* We are loading the backup file, so gschem should ask
212 the user if save it or not when closing the page. */
213 w_current->page_current->CHANGED=1;
216 g_free(full_filename);
217 g_free(full_rcfilename);
219 /* If this was a preview window, reset the directory to the
220 * value it had when f_open was called. Also get rid of component
221 * libraries opened while opening preview window. If the component
222 * is actually selected, they will be re-read later. */
223 if (w_current->wid == -1) {
224 chdir(saved_cwd);
225 g_free(saved_cwd);
228 if (!opened) {
229 return (FALSE);
230 } else {
231 return (TRUE);
235 /*! \brief Closes the schematic file
236 * \par Function Description
237 * Does nothing
239 * \param [in,out] w_current The TOPLEVEL object with schematic to be closed.
241 void f_close(TOPLEVEL *w_current)
246 /*! \brief Save schematic file and close
247 * \par Function Description
248 * This function will save the current schematic file before closing it.
249 * It also deletes the page_current item in the TOPLEVEL structure.
251 * \param [in,out] w_current The TOPLEVEL object containing the schematic.
252 * \param [in] filename The file name to save the schematic to.
254 void f_save_close(TOPLEVEL *w_current, char *filename)
256 o_save(w_current, filename);
257 s_page_delete (w_current, w_current->page_current);
260 /*! \brief Save the schematic file
261 * \par Function Description
262 * This function saves the current schematic file in the w_current object.
264 * \param [in,out] w_current The TOPLEVEL object containing the schematic.
265 * \param [in] filename The file name to save the schematic to.
266 * \return 1 on success, 0 on failure.
268 int f_save(TOPLEVEL *w_current, const char *filename)
270 gchar *backup_filename;
271 gchar *real_filename;
272 gchar *only_filename;
273 gchar *dirname;
274 mode_t saved_umask, mask;
275 struct stat st;
277 /* Get the real filename and file permissions */
278 real_filename = follow_symlinks (filename, NULL);
280 if (real_filename == NULL) {
281 s_log_message ("Can't get the real filename of %s.", filename);
282 fprintf (stderr, "Can't get the real filename of %s.\n", filename);
283 return 0;
286 /* Get the directory in which the real filename lives */
287 dirname = g_path_get_dirname (real_filename);
288 only_filename = g_path_get_basename(real_filename);
290 /* Do a backup if it's not an undo file backup and it was never saved. */
291 if (w_current->page_current->saved_since_first_loaded == 0) {
292 if ( (g_file_test (real_filename, G_FILE_TEST_EXISTS)) &&
293 (!g_file_test(real_filename, G_FILE_TEST_IS_DIR)) )
295 backup_filename = g_strdup_printf("%s%c%s~", dirname,
296 G_DIR_SEPARATOR, only_filename);
298 /* Make the backup file read-write before saving a new one */
299 if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) &&
300 (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) {
301 if (chmod(backup_filename, S_IREAD|S_IWRITE) != 0) {
302 s_log_message ("Could NOT set previous backup file [%s] read-write\n",
303 backup_filename);
307 if (rename(real_filename, backup_filename) != 0) {
308 s_log_message ("Can't save backup file: %s.", backup_filename);
309 fprintf (stderr, "Can't save backup file: %s.", backup_filename);
311 else {
312 /* Make the backup file readonly so a 'rm *' command will ask
313 the user before deleting it */
314 saved_umask = umask(0);
315 mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH);
316 mask = (~mask)&0777;
317 mask &= ((~saved_umask) & 0777);
318 if (chmod(backup_filename, mask) != 0) {
319 s_log_message ("Could NOT set backup file [%s] readonly\n",
320 backup_filename);
322 umask(saved_umask);
325 g_free(backup_filename);
328 /* If there is not an existing file with that name, compute the
329 * permissions and uid/gid that we will use for the newly-created file.
332 if (stat (real_filename, &st) != 0)
334 struct stat dir_st;
335 int result;
337 /* Use default permissions */
338 saved_umask = umask(0);
339 st.st_mode = 0666 & ~saved_umask;
340 umask(saved_umask);
341 st.st_uid = getuid ();
343 result = stat (dirname, &dir_st);
345 if (result == 0 && (dir_st.st_mode & S_ISGID))
346 st.st_gid = dir_st.st_gid;
347 else
348 st.st_gid = getgid ();
350 g_free (dirname);
351 g_free (only_filename);
353 if (o_save(w_current, real_filename)) {
355 w_current->page_current->saved_since_first_loaded = 1;
357 /* Reset the last saved timer */
358 g_get_current_time (&w_current->page_current->last_load_or_save_time);
359 w_current->page_current->ops_since_last_backup = 0;
360 w_current->page_current->do_autosave_backup = 0;
362 /* Restore permissions. */
363 chmod (real_filename, st.st_mode);
364 chown (real_filename, st.st_uid, st.st_gid);
366 g_free (real_filename);
367 return 1;
369 else {
370 g_free (real_filename);
371 return 0;
375 /*! \brief Reformats a filename as an absolute resolved filename
376 * \par Function Description
377 * Given a filename in any format, this returns the full, absolute
378 * resolved filename.
380 * \param [in] filename A character string containing the file
381 * name to resolve.
382 * \return A character string with the resolved filename.
384 char* f_normalize_filename(const gchar *filename)
386 char filename_buffer[MAXPATHLEN]; /* nasty hack for realpath */
387 char *full_filename;
389 /* Check for pathological case */
390 if (filename == NULL) {
391 return NULL;
394 realpath(filename, filename_buffer); /* places reult in filename_buffer */
395 full_filename = g_strdup (filename_buffer);
397 #ifdef DEBUG
398 printf("In f_normalize_filename, returning full_filename= %s \n", full_filename);
399 #endif
401 return full_filename;
404 /*! \brief Follow symlinks until a real file is found
405 * \par Function Description
406 * Does readlink() recursively until we find a real filename.
408 * \param [in] filename The filename to search for.
409 * \param [out] error Unused, set to NULL
410 * \return The path to real file on success, NULL otherwise.
412 * \note Taken from gedit's source code.
414 char *follow_symlinks (const gchar *filename, GError **error)
416 gchar *followed_filename;
417 gint link_count;
419 g_return_val_if_fail (filename != NULL, NULL);
421 g_return_val_if_fail (strlen (filename) + 1 <= MAXPATHLEN, NULL);
423 followed_filename = g_strdup (filename);
424 link_count = 0;
426 while (link_count < MAX_LINK_LEVEL) {
427 struct stat st;
429 if (lstat (followed_filename, &st) != 0)
430 /* We could not access the file, so perhaps it does not
431 * exist. Return this as a real name so that we can
432 * attempt to create the file.
434 return followed_filename;
436 if (S_ISLNK (st.st_mode)) {
437 gint len;
438 gchar linkname[MAXPATHLEN];
440 link_count++;
442 len = readlink (followed_filename, linkname, MAXPATHLEN - 1);
444 if (len == -1) {
445 s_log_message("Could not read symbolic link information for %s", followed_filename);
446 fprintf(stderr, "Could not read symbolic link information for %s", followed_filename);
447 g_free (followed_filename);
448 return NULL;
451 linkname[len] = '\0';
453 /* If the linkname is not an absolute path name, append
454 * it to the directory name of the followed filename. E.g.
455 * we may have /foo/bar/baz.lnk -> eek.txt, which really
456 * is /foo/bar/eek.txt.
459 if (linkname[0] != G_DIR_SEPARATOR) {
460 gchar *slashpos;
461 gchar *tmp;
463 slashpos = strrchr (followed_filename, G_DIR_SEPARATOR);
465 if (slashpos)
466 *slashpos = '\0';
467 else {
468 tmp = g_strconcat ("./", followed_filename, NULL);
469 g_free (followed_filename);
470 followed_filename = tmp;
473 tmp = g_build_filename (followed_filename, linkname, NULL);
474 g_free (followed_filename);
475 followed_filename = tmp;
476 } else {
477 g_free (followed_filename);
478 followed_filename = g_strdup (linkname);
480 } else
481 return followed_filename;
484 /* Too many symlinks */
486 s_log_message("The file has too many symbolic links.");
487 fprintf(stderr, "The file has too many symbolic links.");
489 return NULL;