GnuCash 2.4.99
file-utils.c
00001 /********************************************************************\
00002  * file-utils.c -- simple file utilities                            *
00003  * Copyright (C) 1997 Robin D. Clark <rclark@cs.hmc.edu>            *
00004  * Copyright (C) 1998 Rob Browning                                  *
00005  * Copyright (C) 1998-2000 Linas Vepstas <linas@linas.org>          *
00006  *                                                                  *
00007  * This program is free software; you can redistribute it and/or    *
00008  * modify it under the terms of the GNU General Public License as   *
00009  * published by the Free Software Foundation; either version 2 of   *
00010  * the License, or (at your option) any later version.              *
00011  *                                                                  *
00012  * This program is distributed in the hope that it will be useful,  *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00015  * GNU General Public License for more details.                     *
00016  *                                                                  *
00017  * You should have received a copy of the GNU General Public License*
00018  * along with this program; if not, write to the Free Software      *
00019  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        *
00020 \********************************************************************/
00021 
00022 #include "config.h"
00023 
00024 #include <glib.h>
00025 #include <glib/gstdio.h>
00026 #include <libguile.h>
00027 #include <errno.h>
00028 #include <fcntl.h>
00029 #include <string.h>
00030 #include <sys/stat.h>
00031 #include <sys/types.h>
00032 #ifdef HAVE_UNISTD_H
00033 # include <unistd.h>
00034 #else
00035 # include <io.h>
00036 # define close _close
00037 # define lseek _lseek
00038 # define read _read
00039 #endif
00040 
00041 #include "guile-mappings.h"
00042 #include "file-utils.h"
00043 #include "gnc-engine.h"
00044 #include "gnc-filepath-utils.h"
00045 #include "gnc-gkeyfile-utils.h"
00046 #include "gnc-uri-utils.h"
00047 
00048 /* This static indicates the debugging module that this .o belongs to.  */
00049 static QofLogModule log_module = GNC_MOD_GUILE;
00050 
00051 /********************************************************************\
00052 \********************************************************************/
00053 
00054 char *
00055 gncFindFile (const char * filename)
00056 {
00057     char *full_filename = NULL;
00058     char * return_string = NULL;
00059     SCM find_doc_file;
00060     SCM scm_filename;
00061     SCM scm_result;
00062 
00063     if (!filename || *filename == '\0')
00064         return NULL;
00065 
00066     find_doc_file = scm_c_eval_string("gnc:find-doc-file");
00067     scm_filename = scm_makfrom0str ((char *) filename);
00068     scm_result = scm_call_1(find_doc_file, scm_filename);
00069 
00070     if (scm_is_string(scm_result))
00071     {
00072         char * str;
00073 
00074         scm_dynwind_begin (0);
00075         full_filename = scm_to_locale_string(scm_result);
00076         return_string = g_strdup (full_filename);
00077         scm_dynwind_free (full_filename);
00078         scm_dynwind_end ();
00079     }
00080 
00081     return return_string;
00082 }
00083 
00084 /********************************************************************\
00085  * gncReadFile                                                      *
00086  *                                                                  *
00087  * Args:   filename - the name of the html file to read             *
00088  *         data - pointer to set to the buffer of data read in      *
00089  * Return: size of data read                                        *
00090  * Global: helpPath - the path to the help files                    *
00091 \********************************************************************/
00092 int
00093 gncReadFile (const char * filename, char ** data)
00094 {
00095     char *buf = NULL;
00096     char  *fullname;
00097     int   size = 0;
00098     int   fd;
00099 
00100     /* construct absolute path -- twiddle the relative path we received */
00101     if (!filename || filename[0] == '\0') return 0;
00102 
00103     /* take absolute paths without searching */
00104     if (!g_path_is_absolute (filename))
00105         fullname = gncFindFile (filename);
00106     else
00107         fullname = g_strdup (filename);
00108 
00109     if (!fullname) return 0;
00110 
00111     /* Open file: */
00112     fd = g_open( fullname, O_RDONLY, 0 );
00113 
00114     g_free(fullname);
00115     fullname = NULL;
00116 
00117     if ( fd == -1 )
00118     {
00119         int norr = errno;
00120         PERR ("file %s: (%d) %s \n", filename, norr, strerror(norr));
00121         return 0;
00122     }
00123 
00124     /* Find size: */
00125     size = lseek( fd, 0, SEEK_END );
00126     lseek( fd, 0, SEEK_SET );
00127 
00128     /* Allocate memory */
00129     buf = g_new(char, size + 1);
00130 
00131     /* read in file */
00132     if ( read(fd, buf, size) == -1 )
00133     {
00134         g_free(buf);
00135         buf = NULL;
00136     }
00137     else
00138     {
00139         buf[size] = '\0';
00140     }
00141 
00142     close(fd);
00143     *data = buf;
00144 
00145     return size;
00146 }
00147 
00148 /***********************************************************************
00149  * gnc_getline -- read a line from the input file, up to and including
00150  *                the newline.
00151  *
00152  * Args:   line - pointer to hold the buffer for the whole line (allocated by
00153  *                this function)
00154  *         file - the file from which to read
00155  * Return: the number of bytes read
00156  *
00157  * The caller MUST g_free() the line returned from this call in all
00158  * cases where it is non-NULL!
00159  */
00160 
00161 gint64
00162 gnc_getline (gchar **line, FILE *file)
00163 {
00164     char str[BUFSIZ];
00165     gint64 len;
00166     GString *gs;
00167 
00168     g_return_val_if_fail(line, -1);
00169     *line = NULL;
00170     g_return_val_if_fail(file, -1);
00171 
00172     gs = g_string_new("");
00173 
00174     while (fgets(str, sizeof(str), file) != NULL)
00175     {
00176         g_string_append(gs, str);
00177 
00178         len = strlen(str);
00179         if (str[len-1] == '\n')
00180             break;
00181     }
00182 
00183     len = gs->len;
00184     *line = gs->str;
00185     g_string_free(gs, FALSE);
00186     return len;
00187 }
00188 
00189 /*  Find the state file that corresponds to this URL and guid.
00190  *
00191  * The state files will be searched for in the books directory in GnuCash'
00192  * private configuration directory. This configuration directory is
00193  * platform dependent and can be overridden with environment variable
00194  * DOT_GNUCASH_DIR. On linux for example this is ~/.gnucash by default.
00195  *
00196  * The URL is used to compute the base name of the state file and the
00197  * guid is used to differentiate when the user has multiple data files
00198  * with the same name.
00199  *
00200  * As of GnuCash 2.4.1 state files will have their own extension to
00201  * differentiate them from data files saved by the user. New state
00202  * files will always be created with such an extension. But GnuCash
00203  * will continue to search for state files without an extension if
00204  * no proper state file with extension is found. */
00205 GKeyFile *
00206 gnc_find_state_file (const gchar *url,
00207                      const gchar *guid,
00208                      gchar **filename_p)
00209 {
00210     gchar *basename, *original = NULL, *filename, *tmp, *file_guid;
00211     gchar *sf_extension = NULL, *newstyle_filename = NULL;
00212     GKeyFile *key_file = NULL;
00213     gint i;
00214 
00215     ENTER("url %s, guid %s", url, guid);
00216 
00217     if ( gnc_uri_is_file_uri ( url ) )
00218     {
00219         /* The url is a true file, use its basename. */
00220         gchar *path = gnc_uri_get_path ( url );
00221         basename = g_path_get_basename ( path );
00222         g_free ( path );
00223     }
00224     else
00225     {
00226         /* The url is composed of database connection parameters. */
00227         gchar* protocol = NULL;
00228         gchar* host = NULL;
00229         gchar* dbname = NULL;
00230         gchar* username = NULL;
00231         gchar* password = NULL;
00232         gint portnum = 0;
00233         gnc_uri_get_components ( url, &protocol, &host, &portnum,
00234                                  &username, &password, &dbname );
00235 
00236         basename = g_strjoin("_", protocol, host, username, dbname, NULL);
00237         g_free( protocol );
00238         g_free( host );
00239         g_free( username );
00240         g_free( password );
00241         g_free( dbname );
00242     }
00243 
00244     DEBUG("Basename %s", basename);
00245     original = gnc_build_book_path(basename);
00246     g_free(basename);
00247     DEBUG("Original %s", original);
00248 
00249     sf_extension = g_strdup(STATE_FILE_EXT);
00250     i = 1;
00251     while (1)
00252     {
00253         if (i == 1)
00254             filename = g_strconcat(original, sf_extension, NULL);
00255         else
00256             filename = g_strdup_printf("%s_%d%s", original, i, sf_extension);
00257         DEBUG("Trying %s", filename);
00258         key_file = gnc_key_file_load_from_file(filename, FALSE, FALSE, NULL);
00259         DEBUG("Result %p", key_file);
00260 
00261         if (!key_file)
00262         {
00263             DEBUG("No key file by that name");
00264             if (g_strcmp0(sf_extension, STATE_FILE_EXT) == 0)
00265             {
00266                 DEBUG("Trying old state file names for compatibility");
00267                 newstyle_filename = filename;
00268                 i = 1;
00269                 g_free( sf_extension);
00270                 sf_extension = g_strdup("");
00271                 continue;
00272             }
00273             break;
00274         }
00275 
00276         file_guid = g_key_file_get_string(key_file,
00277                                           STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
00278                                           NULL);
00279         DEBUG("File GncGUID is %s", file_guid ? file_guid : "<not found>");
00280         if (safe_strcmp(guid, file_guid) == 0)
00281         {
00282             DEBUG("Matched !!!");
00283             g_free(file_guid);
00284             break;
00285         }
00286         DEBUG("Clean up this pass");
00287         g_free(file_guid);
00288         g_key_file_free(key_file);
00289         g_free(filename);
00290         i++;
00291     }
00292 
00293     DEBUG("Clean up");
00294     g_free(original);
00295     /* Pre-2.4.1 compatibility block: make sure when the state file is
00296      * written again later, it will use the next available filename with
00297      * extension and optional counter. (This name was determined earlier
00298      * in the loop.) */
00299     if (newstyle_filename)
00300     {
00301         g_free(filename);
00302         filename = newstyle_filename;
00303     }
00304 
00305     if (filename_p)
00306         *filename_p = filename;
00307     else
00308         g_free(filename);
00309     LEAVE("key_file %p, filename %s", key_file,
00310           filename_p ? *filename_p : "(none)");
00311     return key_file;
00312 }
00313 
00314 /* ----------------------- END OF FILE ---------------------  */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines