Code

Replaced two tests with CxxTest versions.
[inkscape.git] / src / io / sys.cpp
2 /*
3  * System abstraction utility routines
4  *
5  * Authors:
6  *   Jon A. Cruz <jon@joncruz.org>
7  *
8  * Copyright (C) 2004-2005 Authors
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
18 #include <glib/gutils.h>
19 #if GLIB_CHECK_VERSION(2,6,0)
20     #include <glib/gstdio.h>
21 #endif
22 #include <glibmm/ustring.h>
23 #include <gtk/gtkmessagedialog.h>
25 #include "prefs-utils.h"
26 #include "sys.h"
28 #ifdef WIN32
30 // For now to get at is_os_wide().
31 #include "extension/internal/win32.h"
32 using Inkscape::Extension::Internal::PrintWin32;
34 #endif
36 //#define INK_DUMP_FILENAME_CONV 1
37 #undef INK_DUMP_FILENAME_CONV
39 //#define INK_DUMP_FOPEN 1
40 #undef INK_DUMP_FOPEN
42 void dump_str(gchar const *str, gchar const *prefix);
43 void dump_ustr(Glib::ustring const &ustr);
45 extern guint update_in_progress;
48 #define DEBUG_MESSAGE(key, ...) \
49 {\
50     gint dump = prefs_get_int_attribute_limited("options.bulia", #key, 0, 0, 1);\
51     gint dumpD = prefs_get_int_attribute_limited("options.bulia", #key"D", 0, 0, 1);\
52     gint dumpD2 = prefs_get_int_attribute_limited("options.bulia", #key"D2", 0, 0, 1);\
53     dumpD &= ( (update_in_progress == 0) || dumpD2 );\
54     if ( dump )\
55     {\
56         g_message( __VA_ARGS__ );\
57 \
58     }\
59     if ( dumpD )\
60     {\
61         GtkWidget *dialog = gtk_message_dialog_new(NULL,\
62                                                    GTK_DIALOG_DESTROY_WITH_PARENT, \
63                                                    GTK_MESSAGE_INFO,    \
64                                                    GTK_BUTTONS_OK,      \
65                                                    __VA_ARGS__          \
66                                                    );\
67         g_signal_connect_swapped(dialog, "response",\
68                                  G_CALLBACK(gtk_widget_destroy),        \
69                                  dialog);                               \
70         gtk_widget_show_all( dialog );\
71     }\
72 }
77 void Inkscape::IO::dump_fopen_call( char const *utf8name, char const *id )
78 {
79 #ifdef INK_DUMP_FOPEN
80     Glib::ustring str;
81     for ( int i = 0; utf8name[i]; i++ )
82     {
83         if ( utf8name[i] == '\\' )
84         {
85             str += "\\\\";
86         }
87         else if ( (utf8name[i] >= 0x20) && ((0x0ff & utf8name[i]) <= 0x7f) )
88         {
89             str += utf8name[i];
90         }
91         else
92         {
93             gchar tmp[32];
94             g_snprintf( tmp, sizeof(tmp), "\\x%02x", (0x0ff & utf8name[i]) );
95             str += tmp;
96         }
97     }
98     g_message( "fopen call %s for [%s]", id, str.data() );
99 #endif
102 FILE *Inkscape::IO::fopen_utf8name( char const *utf8name, char const *mode )
104     static gint counter = 0;
105     FILE* fp = NULL;
107     DEBUG_MESSAGE( dumpOne, "entering fopen_utf8name( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
109 #ifndef WIN32
110     DEBUG_MESSAGE( dumpOne, "           STEP 0              ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
111     gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
112     if ( filename )
113     {
114         DEBUG_MESSAGE( dumpOne, "           STEP 1              ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
115         fp = std::fopen(filename, mode);
116         DEBUG_MESSAGE( dumpOne, "           STEP 2              ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
117         g_free(filename);
118         DEBUG_MESSAGE( dumpOne, "           STEP 3              ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
119         filename = 0;
120     }
121 #else
122     Glib::ustring how( mode );
123     how.append("b");
124     DEBUG_MESSAGE( dumpOne, "   calling is_os_wide()       ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
126     fp = g_fopen(utf8name, how.c_str());
127 #endif
129     DEBUG_MESSAGE( dumpOne, "leaving fopen_utf8name( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
131     return fp;
135 int Inkscape::IO::mkdir_utf8name( char const *utf8name )
137     static gint counter = 0;
138     int retval = -1;
140     DEBUG_MESSAGE( dumpMk, "entering mkdir_utf8name( '%s' )[%d]", utf8name, (counter++) );
142 #ifndef WIN32
143     DEBUG_MESSAGE( dumpMk, "           STEP 0              ( '%s' )[%d]", utf8name, (counter++) );
144     gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
145     if ( filename )
146     {
147         DEBUG_MESSAGE( dumpMk, "           STEP 1              ( '%s' )[%d]", utf8name, (counter++) );
148         retval = ::mkdir(filename, S_IRWXU | S_IRGRP | S_IXGRP);
149         DEBUG_MESSAGE( dumpMk, "           STEP 2              ( '%s' )[%d]", utf8name, (counter++) );
150         g_free(filename);
151         DEBUG_MESSAGE( dumpMk, "           STEP 3              ( '%s' )[%d]", utf8name, (counter++) );
152         filename = 0;
153     }
154 #else
155     DEBUG_MESSAGE( dumpMk, "   calling is_os_wide()       ( '%s' )[%d]", utf8name, (counter++) );
157     // Mode should be ingnored inside of glib on the way in
158     retval = g_mkdir( utf8name, 0 );
159 #endif
161     DEBUG_MESSAGE( dumpMk, "leaving mkdir_utf8name( '%s' )[%d]", utf8name, (counter++) );
163     return retval;
166 bool Inkscape::IO::file_test( char const *utf8name, GFileTest test )
168     bool exists = false;
170     if ( utf8name ) {
171         gchar *filename = NULL;
172         if (utf8name && !g_utf8_validate(utf8name, -1, NULL)) {
173             /* FIXME: Trying to guess whether or not a filename is already in utf8 is unreliable.
174                If any callers pass non-utf8 data (e.g. using g_get_home_dir), then change caller to
175                use simple g_file_test.  Then add g_return_val_if_fail(g_utf_validate(...), false)
176                to beginning of this function. */
177             filename = g_strdup(utf8name);
178             // Looks like g_get_home_dir isn't safe.
179             //g_warning("invalid UTF-8 detected internally. HUNT IT DOWN AND KILL IT!!!");
180         } else {
181             filename = g_filename_from_utf8 ( utf8name, -1, NULL, NULL, NULL );
182         }
183         if ( filename ) {
184             exists = g_file_test (filename, test);
185             g_free(filename);
186             filename = NULL;
187         } else {
188             g_warning( "Unable to convert filename in IO:file_test" );
189         }
190     }
192     return exists;
195 /** Wrapper around g_dir_open, but taking a utf8name as first argument. */
196 GDir *
197 Inkscape::IO::dir_open(gchar const *const utf8name, guint const flags, GError **const error)
199     gchar *const opsys_name = g_filename_from_utf8(utf8name, -1, NULL, NULL, error);
200     if (opsys_name) {
201         GDir *ret = g_dir_open(opsys_name, flags, error);
202         g_free(opsys_name);
203         return ret;
204     } else {
205         return NULL;
206     }
209 /**
210  * Like g_dir_read_name, but returns a utf8name (which must be freed, unlike g_dir_read_name).
211  *
212  * N.B. Skips over any dir entries that fail to convert to utf8.
213  */
214 gchar *
215 Inkscape::IO::dir_read_utf8name(GDir *dir)
217     for (;;) {
218         gchar const *const opsys_name = g_dir_read_name(dir);
219         if (!opsys_name) {
220             return NULL;
221         }
222         gchar *utf8_name = g_filename_to_utf8(opsys_name, -1, NULL, NULL, NULL);
223         if (utf8_name) {
224             return utf8_name;
225         }
226     }
230 gchar* Inkscape::IO::locale_to_utf8_fallback( const gchar *opsysstring,
231                                               gssize len,
232                                               gsize *bytes_read,
233                                               gsize *bytes_written,
234                                               GError **error )
236     gchar *result = NULL;
237     if ( opsysstring ) {
238         gchar *newFileName = g_locale_to_utf8( opsysstring, len, bytes_read, bytes_written, error );
239         if ( newFileName ) {
240             if ( !g_utf8_validate(newFileName, -1, NULL) ) {
241                 g_warning( "input filename did not yield UTF-8" );
242                 g_free( newFileName );
243             } else {
244                 result = newFileName;
245             }
246             newFileName = 0;
247         } else if ( g_utf8_validate(opsysstring, -1, NULL) ) {
248             // This *might* be a case that we want
249             // g_warning( "input failed filename->utf8, fell back to original" );
250             // TODO handle cases when len >= 0
251             result = g_strdup( opsysstring );
252         } else {
253             gchar const *charset = 0;
254             g_get_charset(&charset);
255             g_warning( "input filename conversion failed for file with locale charset '%s'", charset );
256         }
257     }
258     return result;
262 gchar* Inkscape::IO::sanitizeString( gchar const * str )
264     gchar *result = NULL;
265     if ( str ) {
266         if ( g_utf8_validate(str, -1, NULL) ) {
267             result = g_strdup(str);
268         } else {
269             guchar scratch[8];
270             Glib::ustring buf;
271             guchar const *ptr = (guchar const*)str;
272             while ( *ptr )
273             {
274                 if ( *ptr == '\\' )
275                 {
276                     buf.append("\\\\");
277                 } else if ( *ptr < 0x80 ) {
278                     buf += (char)(*ptr);
279                 } else {
280                     g_snprintf((gchar*)scratch, sizeof(scratch), "\\x%02x", *ptr);
281                     buf.append((const char*)scratch);
282                 }
283                 ptr++;
284             }
285             result = g_strdup(buf.c_str());
286         }
287     }
288     return result;
291 /*
292   Local Variables:
293   mode:c++
294   c-file-style:"stroustrup"
295   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
296   indent-tabs-mode:nil
297   fill-column:99
298   End:
299 */
300 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :