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
27 #include <sys/param.h>
31 #include <sys/types.h>
44 #include "../include/prototype.h"
46 #ifdef HAVE_LIBDMALLOC
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
58 * \return 0 on failure, 1 on success.
60 int f_open(TOPLEVEL
*w_current
, char *filename
)
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
);
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
,
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
;
128 if (stat (backup_filename
, &stat_backup
) != 0) {
129 s_log_message ("f_open: Unable to get stat information of backup file %s.",
133 if (stat (full_filename
, &stat_file
) != 0) {
134 s_log_message ("f_open: Unable to get stat information of file %s.",
138 if ((difftime (stat_file
.st_ctime
, stat_backup
.st_ctime
) < 0) ||
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");
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");
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
,
179 /* Load the original file */
180 w_current
->page_current
->object_tail
= (OBJECT
*)
181 o_read(w_current
, w_current
->page_current
->object_tail
,
185 g_free (backup_filename
);
187 if (w_current
->page_current
->object_tail
!= NULL
) {
188 s_log_message("Opened file [%s]\n", full_filename
);
192 /* Failed to open page */
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 */
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 */
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) {
235 /*! \brief Closes the schematic file
236 * \par Function Description
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
;
274 mode_t saved_umask
, mask
;
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
);
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",
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
);
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
);
317 mask
&= ((~saved_umask
) & 0777);
318 if (chmod(backup_filename
, mask
) != 0) {
319 s_log_message ("Could NOT set backup file [%s] readonly\n",
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)
337 /* Use default permissions */
338 saved_umask
= umask(0);
339 st
.st_mode
= 0666 & ~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
;
348 st
.st_gid
= getgid ();
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
);
370 g_free (real_filename
);
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
380 * \param [in] filename A character string containing the file
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 */
389 /* Check for pathological case */
390 if (filename
== NULL
) {
394 realpath(filename
, filename_buffer
); /* places reult in filename_buffer */
395 full_filename
= g_strdup (filename_buffer
);
398 printf("In f_normalize_filename, returning full_filename= %s \n", full_filename
);
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
;
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
);
426 while (link_count
< MAX_LINK_LEVEL
) {
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
)) {
438 gchar linkname
[MAXPATHLEN
];
442 len
= readlink (followed_filename
, linkname
, MAXPATHLEN
- 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
);
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
) {
463 slashpos
= strrchr (followed_filename
, G_DIR_SEPARATOR
);
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
;
477 g_free (followed_filename
);
478 followed_filename
= g_strdup (linkname
);
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.");