1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
28 #include <sys/param.h>
32 #include <sys/types.h>
45 #include "../include/prototype.h"
47 #ifdef HAVE_LIBDMALLOC
51 /*! \brief Opens the schematic file.
52 * \par Function Description
53 * Opens the schematic file by calling f_open_flags() with the
54 * F_OPEN_RC and F_OPEN_CHECK_BACKUP flags.
56 * \param [in,out] w_current The TOPLEVEL object to load the schematic into.
57 * \param [in] filename A character string containing the file name
59 * \return 0 on failure, 1 on success.
61 int f_open(TOPLEVEL
*w_current
, const gchar
*filename
)
63 return f_open_flags (w_current
, filename
,
64 F_OPEN_RC
| F_OPEN_CHECK_BACKUP
);
67 /*! \brief Opens the schematic file with fine-grained control over behaviour.
68 * \par Function Description
69 * Opens the schematic file and carries out a number of actions
70 * depending on the \a flags set. If #F_OPEN_RC is set, executes
71 * configuration files found in the target directory. If
72 * #F_OPEN_CHECK_BACKUP is set, warns user if a backup is found for
73 * the file being loaded, and possibly prompts user for whether to
74 * load the backup instead. If #F_OPEN_RESTORE_CWD is set, does not
75 * change the working directory to that of the file being loaded.
77 * \param [in,out] w_current The TOPLEVEL object to load the schematic into.
78 * \param [in] filename A character string containing the file name
80 * \param [in] flags Combination of #FOpenFlags values.
81 * \return 0 on failure, 1 on success.
83 int f_open_flags(TOPLEVEL
*w_current
, const gchar
*filename
,
87 char *full_filename
= NULL
;
88 char *full_rcfilename
= NULL
;
89 char *file_directory
= NULL
;
90 char *saved_cwd
= NULL
;
91 char *backup_filename
= NULL
;
92 char load_backup_file
= 0;
94 /* has the head been freed yet? */
95 /* probably not hack PAGE */
97 set_window(w_current
, w_current
->page_current
,
98 w_current
->init_left
, w_current
->init_right
,
99 w_current
->init_top
, w_current
->init_bottom
);
102 /* Cache the cwd so we can restore it later. */
103 /*! \bug Assumes cwd will be less than 1024 characters. */
104 if (flags
& F_OPEN_RESTORE_CWD
) {
105 saved_cwd
= getcwd(NULL
, 1024);
108 /* get full, absolute path to file */
109 full_filename
= f_normalize_filename(filename
);
111 /* write full, absolute filename into page_current->page_filename */
112 if (w_current
->page_current
->page_filename
) {
113 g_free(w_current
->page_current
->page_filename
);
115 w_current
->page_current
->page_filename
= g_strdup(full_filename
);
117 /* Before we open the page, let's load the corresponding gafrc. */
118 /* First cd into file's directory. */
119 file_directory
= g_dirname (full_filename
);
121 if (file_directory
) {
122 chdir(file_directory
);
123 /*! \bug Probably should do some checking of chdir return values */
126 /* Now open RC and process file */
127 if (flags
& F_OPEN_RC
) {
128 full_rcfilename
= g_strconcat (file_directory
,
132 g_rc_parse_specified_rc(w_current
, full_rcfilename
);
135 if (flags
& F_OPEN_CHECK_BACKUP
) {
136 /* Check if there is a newer autosave backup file */
138 = g_strdup_printf("%s%c"AUTOSAVE_BACKUP_FILENAME_STRING
,
139 file_directory
, G_DIR_SEPARATOR
,
140 g_path_get_basename(full_filename
));
142 g_free (file_directory
);
144 if ( g_file_test (backup_filename
, G_FILE_TEST_EXISTS
) &&
145 (! g_file_test (backup_filename
, G_FILE_TEST_IS_DIR
))) {
146 /* An autosave backup file exists. Check if it's newer */
147 struct stat stat_backup
;
148 struct stat stat_file
;
152 if (stat (backup_filename
, &stat_backup
) != 0) {
153 s_log_message ("f_open: Unable to get stat information of backup file %s.",
157 if (stat (full_filename
, &stat_file
) != 0) {
158 s_log_message ("f_open: Unable to get stat information of file %s.",
162 if ((difftime (stat_file
.st_ctime
, stat_backup
.st_ctime
) < 0) ||
165 /* Found an autosave backup. It's newer if error_stat is 0 */
166 message
= g_string_new ("");
167 g_string_append_printf(message
, "\nWARNING: Found an autosave backup file:\n %s.\n\n", backup_filename
);
168 if (error_stat
== 1) {
169 g_string_append(message
, "I could not guess if it is newer, so you have to"
170 "do it manually.\n");
173 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");
175 g_string_append (message
, "Gschem usually makes backup copies automatically, and this situation happens when it crashed or it was forced to exit abruptly.\n");
176 if (w_current
->page_current
->load_newer_backup_func
== NULL
) {
177 s_log_message(message
->str
);
178 s_log_message("\nRun gschem and correct the situation.\n\n");
179 fprintf(stderr
, message
->str
);
180 fprintf(stderr
, "\nRun gschem and correct the situation.\n\n");
183 /* Ask the user if load the backup or the original file */
184 if (w_current
->page_current
->load_newer_backup_func
185 (w_current
, message
)) {
186 /* Load the backup file */
187 load_backup_file
= 1;
190 g_string_free (message
, TRUE
);
195 /* Now that we have set the current directory and read
196 * the RC file, it's time to read in the file. */
197 if (load_backup_file
== 1) {
198 /* Load the backup file */
199 w_current
->page_current
->object_tail
= (OBJECT
*)
200 o_read(w_current
, w_current
->page_current
->object_tail
,
204 /* Load the original file */
205 w_current
->page_current
->object_tail
= (OBJECT
*)
206 o_read(w_current
, w_current
->page_current
->object_tail
,
210 if (w_current
->page_current
->object_tail
!= NULL
) {
211 s_log_message("Opened file [%s]\n", full_filename
);
214 /* Failed to open page */
218 w_current
->page_current
->object_tail
219 = (OBJECT
*) return_tail(w_current
->page_current
->object_head
);
221 /* make sure you init net_consolide to false (default) in all */
223 if (w_current
->net_consolidate
== TRUE
) {
224 o_net_consolidate(w_current
);
227 if (load_backup_file
== 0) {
228 /* If it's not the backup file */
229 w_current
->page_current
->CHANGED
=0; /* added 4/7/98 */
232 /* We are loading the backup file, so gschem should ask
233 the user if save it or not when closing the page. */
234 w_current
->page_current
->CHANGED
=1;
237 g_free(full_filename
);
238 g_free(full_rcfilename
);
239 g_free (backup_filename
);
241 /* Reset the directory to the value it had when f_open was
243 if (flags
& F_OPEN_RESTORE_CWD
) {
255 /*! \brief Closes the schematic file
256 * \par Function Description
259 * \param [in,out] w_current The TOPLEVEL object with schematic to be closed.
261 void f_close(TOPLEVEL
*w_current
)
266 /*! \brief Save schematic file and close
267 * \par Function Description
268 * This function will save the current schematic file before closing it.
269 * It also deletes the page_current item in the TOPLEVEL structure.
271 * \param [in,out] w_current The TOPLEVEL object containing the schematic.
272 * \param [in] filename The file name to save the schematic to.
274 void f_save_close(TOPLEVEL
*w_current
, char *filename
)
276 o_save(w_current
, filename
);
277 s_page_delete (w_current
, w_current
->page_current
);
280 /*! \brief Save the schematic file
281 * \par Function Description
282 * This function saves the current schematic file in the w_current object.
284 * \param [in,out] w_current The TOPLEVEL object containing the schematic.
285 * \param [in] filename The file name to save the schematic to.
286 * \return 1 on success, 0 on failure.
288 int f_save(TOPLEVEL
*w_current
, const char *filename
)
290 gchar
*backup_filename
;
291 gchar
*real_filename
;
292 gchar
*only_filename
;
294 mode_t saved_umask
, mask
;
297 /* Get the real filename and file permissions */
298 real_filename
= follow_symlinks (filename
, NULL
);
300 if (real_filename
== NULL
) {
301 s_log_message ("Can't get the real filename of %s.", filename
);
302 fprintf (stderr
, "Can't get the real filename of %s.\n", filename
);
306 /* Get the directory in which the real filename lives */
307 dirname
= g_path_get_dirname (real_filename
);
308 only_filename
= g_path_get_basename(real_filename
);
310 /* Do a backup if it's not an undo file backup and it was never saved. */
311 if (w_current
->page_current
->saved_since_first_loaded
== 0) {
312 if ( (g_file_test (real_filename
, G_FILE_TEST_EXISTS
)) &&
313 (!g_file_test(real_filename
, G_FILE_TEST_IS_DIR
)) )
315 backup_filename
= g_strdup_printf("%s%c%s~", dirname
,
316 G_DIR_SEPARATOR
, only_filename
);
318 /* Make the backup file read-write before saving a new one */
319 if ( g_file_test (backup_filename
, G_FILE_TEST_EXISTS
) &&
320 (! g_file_test (backup_filename
, G_FILE_TEST_IS_DIR
))) {
321 if (chmod(backup_filename
, S_IREAD
|S_IWRITE
) != 0) {
322 s_log_message ("Could NOT set previous backup file [%s] read-write\n",
327 if (rename(real_filename
, backup_filename
) != 0) {
328 s_log_message ("Can't save backup file: %s.", backup_filename
);
329 fprintf (stderr
, "Can't save backup file: %s.", backup_filename
);
332 /* Make the backup file readonly so a 'rm *' command will ask
333 the user before deleting it */
334 saved_umask
= umask(0);
335 mask
= (S_IWRITE
|S_IWGRP
|S_IEXEC
|S_IXGRP
|S_IXOTH
);
337 mask
&= ((~saved_umask
) & 0777);
338 if (chmod(backup_filename
, mask
) != 0) {
339 s_log_message ("Could NOT set backup file [%s] readonly\n",
345 g_free(backup_filename
);
348 /* If there is not an existing file with that name, compute the
349 * permissions and uid/gid that we will use for the newly-created file.
352 if (stat (real_filename
, &st
) != 0)
357 /* Use default permissions */
358 saved_umask
= umask(0);
359 st
.st_mode
= 0666 & ~saved_umask
;
362 st
.st_uid
= getuid ();
364 result
= stat (dirname
, &dir_st
);
366 if (result
== 0 && (dir_st
.st_mode
& S_ISGID
))
367 st
.st_gid
= dir_st
.st_gid
;
369 st
.st_gid
= getgid ();
370 #endif /* HAVE_CHOWN */
373 g_free (only_filename
);
375 if (o_save(w_current
, real_filename
)) {
377 w_current
->page_current
->saved_since_first_loaded
= 1;
379 /* Reset the last saved timer */
380 g_get_current_time (&w_current
->page_current
->last_load_or_save_time
);
381 w_current
->page_current
->ops_since_last_backup
= 0;
382 w_current
->page_current
->do_autosave_backup
= 0;
384 /* Restore permissions. */
385 chmod (real_filename
, st
.st_mode
);
387 chown (real_filename
, st
.st_uid
, st
.st_gid
);
390 g_free (real_filename
);
394 g_free (real_filename
);
399 /*! \brief Reformats a filename as an absolute resolved filename
400 * \par Function Description
401 * Given a filename in any format, this returns the full, absolute
404 * \param [in] filename A character string containing the file
406 * \return A character string with the resolved filename.
408 char* f_normalize_filename(const gchar
*filename
)
410 char filename_buffer
[MAXPATHLEN
]; /* nasty hack for realpath */
413 /* Check for pathological case */
414 if (filename
== NULL
) {
418 realpath(filename
, filename_buffer
); /* places reult in filename_buffer */
419 full_filename
= g_strdup (filename_buffer
);
422 printf("In f_normalize_filename, returning full_filename= %s \n", full_filename
);
425 return full_filename
;
428 /*! \brief Follow symlinks until a real file is found
429 * \par Function Description
430 * Does readlink() recursively until we find a real filename.
432 * \param [in] filename The filename to search for.
433 * \param [out] error Unused, set to NULL
434 * \return The path to real file on success, NULL otherwise.
436 * \note Taken from gedit's source code.
438 char *follow_symlinks (const gchar
*filename
, GError
**error
)
440 gchar
*followed_filename
;
443 g_return_val_if_fail (filename
!= NULL
, NULL
);
445 g_return_val_if_fail (strlen (filename
) + 1 <= MAXPATHLEN
, NULL
);
447 followed_filename
= g_strdup (filename
);
450 while (link_count
< MAX_LINK_LEVEL
) {
453 if (lstat (followed_filename
, &st
) != 0)
454 /* We could not access the file, so perhaps it does not
455 * exist. Return this as a real name so that we can
456 * attempt to create the file.
458 return followed_filename
;
460 if (S_ISLNK (st
.st_mode
)) {
462 gchar linkname
[MAXPATHLEN
];
466 len
= readlink (followed_filename
, linkname
, MAXPATHLEN
- 1);
469 s_log_message("Could not read symbolic link information for %s", followed_filename
);
470 fprintf(stderr
, "Could not read symbolic link information for %s", followed_filename
);
471 g_free (followed_filename
);
475 linkname
[len
] = '\0';
477 /* If the linkname is not an absolute path name, append
478 * it to the directory name of the followed filename. E.g.
479 * we may have /foo/bar/baz.lnk -> eek.txt, which really
480 * is /foo/bar/eek.txt.
483 if (linkname
[0] != G_DIR_SEPARATOR
) {
487 slashpos
= strrchr (followed_filename
, G_DIR_SEPARATOR
);
492 tmp
= g_strconcat ("./", followed_filename
, NULL
);
493 g_free (followed_filename
);
494 followed_filename
= tmp
;
497 tmp
= g_build_filename (followed_filename
, linkname
, NULL
);
498 g_free (followed_filename
);
499 followed_filename
= tmp
;
501 g_free (followed_filename
);
502 followed_filename
= g_strdup (linkname
);
505 return followed_filename
;
508 /* Too many symlinks */
510 s_log_message("The file has too many symbolic links.");
511 fprintf(stderr
, "The file has too many symbolic links.");