Code

r14583@tres: ted | 2007-02-28 19:29:48 -0800
[inkscape.git] / src / main.cpp
1 #define __MAIN_C__
3 /** \file
4  * Inkscape - an ambitious vector drawing program
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   Frank Felfe <innerspace@iname.com>
9  *   Davide Puricelli <evo@debian.org>
10  *   Mitsuru Oka <oka326@parkcity.ne.jp>
11  *   Masatake YAMATO  <jet@gyve.org>
12  *   F.J.Franklin <F.J.Franklin@sheffield.ac.uk>
13  *   Michael Meeks <michael@helixcode.com>
14  *   Chema Celorio <chema@celorio.com>
15  *   Pawel Palucha
16  *   Bryce Harrington <bryce@bryceharrington.com>
17  * ... and various people who have worked with various projects
18  *
19  * Copyright (C) 1999-2004 authors
20  * Copyright (C) 2001-2002 Ximian, Inc.
21  *
22  * Released under GNU GPL, read the file 'COPYING' for more information
23  */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29 #include "path-prefix.h"
31 #include <gtk/gtkmessagedialog.h>
33 #ifdef HAVE_IEEEFP_H
34 #include <ieeefp.h>
35 #endif
36 #include <string.h>
37 #include <locale.h>
39 #include <popt.h>
40 #ifndef POPT_TABLEEND
41 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
42 #endif /* Not def: POPT_TABLEEND */
44 #include <libxml/tree.h>
45 #include <glib-object.h>
46 #include <gtk/gtkmain.h>
47 #include <gtk/gtksignal.h>
48 #include <gtk/gtkwindow.h>
49 #include <gtk/gtkbox.h>
51 #include "gc-core.h"
53 #include "macros.h"
54 #include "file.h"
55 #include "document.h"
56 #include "sp-object.h"
57 #include "interface.h"
58 #include "print.h"
59 #include "slideshow.h"
60 #include "color.h"
61 #include "sp-item.h"
62 #include "sp-root.h"
63 #include "unit-constants.h"
65 #include "svg/svg.h"
66 #include "svg/svg-color.h"
67 #include "svg/stringstream.h"
69 #include "inkscape-private.h"
70 #include "inkscape-stock.h"
71 #include "inkscape_version.h"
73 #include "sp-namedview.h"
74 #include "sp-guide.h"
75 #include "sp-object-repr.h"
76 #include "xml/repr.h"
78 #include "io/sys.h"
80 #include "debug/logger.h"
82 #include "helper/png-write.h"
84 #include <extension/extension.h>
85 #include <extension/system.h>
86 #include <extension/db.h>
87 #include <extension/output.h>
89 #ifdef WIN32
90 //#define REPLACEARGS_ANSI
91 //#define REPLACEARGS_DEBUG
93 #include "registrytool.h"
95 #include "extension/internal/win32.h"
96 using Inkscape::Extension::Internal::PrintWin32;
98 #endif // WIN32
100 #include "extension/init.h"
102 #include <glibmm/i18n.h>
103 #include <gtkmm/main.h>
105 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
106 #define bind_textdomain_codeset(p,c)
107 #endif
109 #include "application/application.h"
111 enum {
112     SP_ARG_NONE,
113     SP_ARG_NOGUI,
114     SP_ARG_GUI,
115     SP_ARG_FILE,
116     SP_ARG_PRINT,
117     SP_ARG_EXPORT_PNG,
118     SP_ARG_EXPORT_DPI,
119     SP_ARG_EXPORT_AREA,
120     SP_ARG_EXPORT_AREA_DRAWING,
121     SP_ARG_EXPORT_AREA_CANVAS,
122     SP_ARG_EXPORT_AREA_SNAP,
123     SP_ARG_EXPORT_WIDTH,
124     SP_ARG_EXPORT_HEIGHT,
125     SP_ARG_EXPORT_ID,
126     SP_ARG_EXPORT_ID_ONLY,
127     SP_ARG_EXPORT_USE_HINTS,
128     SP_ARG_EXPORT_BACKGROUND,
129     SP_ARG_EXPORT_BACKGROUND_OPACITY,
130     SP_ARG_EXPORT_SVG,
131     SP_ARG_EXPORT_PS,
132     SP_ARG_EXPORT_EPS,
133     SP_ARG_EXPORT_PDF,
134     SP_ARG_EXPORT_TEXT_TO_PATH,
135     SP_ARG_EXPORT_FONT,
136     SP_ARG_EXPORT_BBOX_PAGE,
137     SP_ARG_EXTENSIONDIR,
138     SP_ARG_FIT_PAGE_TO_DRAWING,
139     SP_ARG_SLIDESHOW,
140     SP_ARG_QUERY_X,
141     SP_ARG_QUERY_Y,
142     SP_ARG_QUERY_WIDTH,
143     SP_ARG_QUERY_HEIGHT,
144     SP_ARG_QUERY_ID,
145     SP_ARG_VERSION,
146     SP_ARG_VACUUM_DEFS,
147     SP_ARG_VERB_LIST,
148     SP_ARG_VERB,
149     SP_ARG_SELECT,
150     SP_ARG_LAST
151 };
153 int sp_main_gui(int argc, char const **argv);
154 int sp_main_console(int argc, char const **argv);
155 static void sp_do_export_png(SPDocument *doc);
156 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
157 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const *mime);
158 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
161 static gchar *sp_global_printer = NULL;
162 static gboolean sp_global_slideshow = FALSE;
163 static gchar *sp_export_png = NULL;
164 static gchar *sp_export_dpi = NULL;
165 static gchar *sp_export_area = NULL;
166 static gboolean sp_export_area_drawing = FALSE;
167 static gboolean sp_export_area_canvas = FALSE;
168 static gchar *sp_export_width = NULL;
169 static gchar *sp_export_height = NULL;
170 static gchar *sp_export_id = NULL;
171 static gchar *sp_export_background = NULL;
172 static gchar *sp_export_background_opacity = NULL;
173 static gboolean sp_export_area_snap = FALSE;
174 static gboolean sp_export_use_hints = FALSE;
175 static gboolean sp_export_id_only = FALSE;
176 static gchar *sp_export_svg = NULL;
177 static gchar *sp_export_ps = NULL;
178 static gchar *sp_export_eps = NULL;
179 static gchar *sp_export_pdf = NULL;
180 static gboolean sp_export_text_to_path = FALSE;
181 static gboolean sp_export_font = FALSE;
182 static gboolean sp_export_bbox_page = FALSE;
183 static gboolean sp_query_x = FALSE;
184 static gboolean sp_query_y = FALSE;
185 static gboolean sp_query_width = FALSE;
186 static gboolean sp_query_height = FALSE;
187 static gchar *sp_query_id = NULL;
188 static int sp_new_gui = FALSE;
189 static gboolean sp_vacuum_defs = FALSE;
191 static gchar *sp_export_png_utf8 = NULL;
192 static gchar *sp_export_svg_utf8 = NULL;
193 static gchar *sp_global_printer_utf8 = NULL;
195 #ifdef WIN32
196 static bool replaceArgs( int& argc, char**& argv );
197 #endif
198 static GSList *sp_process_args(poptContext ctx);
199 struct poptOption options[] = {
200     {"version", 'V',
201      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
202      N_("Print the Inkscape version number"),
203      NULL},
205     {"without-gui", 'z',
206      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
207      N_("Do not use X server (only process files from console)"),
208      NULL},
210     {"with-gui", 'g',
211      POPT_ARG_NONE, NULL, SP_ARG_GUI,
212      N_("Try to use X server (even if $DISPLAY is not set)"),
213      NULL},
215     {"file", 'f',
216      POPT_ARG_STRING, NULL, SP_ARG_FILE,
217      N_("Open specified document(s) (option string may be excluded)"),
218      N_("FILENAME")},
220     {"print", 'p',
221      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
222      N_("Print document(s) to specified output file (use '| program' for pipe)"),
223      N_("FILENAME")},
225     {"export-png", 'e',
226      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
227      N_("Export document to a PNG file"),
228      N_("FILENAME")},
230     {"export-dpi", 'd',
231      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
232      N_("The resolution used for exporting SVG into bitmap (default 90)"),
233      N_("DPI")},
235     {"export-area", 'a',
236      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
237      N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
238      N_("x0:y0:x1:y1")},
240     {"export-area-drawing", 'D',
241      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
242      N_("Exported area is the entire drawing (not canvas)"),
243      NULL},
245     {"export-area-canvas", 'C',
246      POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
247      N_("Exported area is the entire canvas"),
248      NULL},
250     {"export-area-snap", 0,
251      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
252      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
253      NULL},
255     {"export-width", 'w',
256      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
257      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
258      N_("WIDTH")},
260     {"export-height", 'h',
261      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
262      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
263      N_("HEIGHT")},
265     {"export-id", 'i',
266      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
267      N_("The ID of the object to export"),
268      N_("ID")},
270     {"export-id-only", 'j',
271      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
272      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
273      //  See "man inkscape" for details.
274      N_("Export just the object with export-id, hide all others (only with export-id)"),
275      NULL},
277     {"export-use-hints", 't',
278      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
279      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
280      NULL},
282     {"export-background", 'b',
283      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
284      N_("Background color of exported bitmap (any SVG-supported color string)"),
285      N_("COLOR")},
287     {"export-background-opacity", 'y',
288      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
289      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
290      N_("VALUE")},
292     {"export-plain-svg", 'l',
293      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
294      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
295      N_("FILENAME")},
297     {"export-ps", 'P',
298      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
299      N_("Export document to a PS file"),
300      N_("FILENAME")},
302     {"export-eps", 'E',
303      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
304      N_("Export document to an EPS file"),
305      N_("FILENAME")},
307     {"export-pdf", 'A',
308      POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
309      N_("Export document to a PDF file"),
310      N_("FILENAME")},
312     {"export-text-to-path", 'T',
313      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
314      N_("Convert text object to paths on export (EPS)"),
315      NULL},
317     {"export-embed-fonts", 'F',
318      POPT_ARG_NONE, &sp_export_font, SP_ARG_EXPORT_FONT,
319      N_("Embed fonts on export (Type 1 only) (EPS)"),
320      NULL},
322     {"export-bbox-page", 'B',
323      POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
324      N_("Export files with the bounding box set to the page size (EPS)"),
325      NULL},
327     {"query-x", 'X',
328      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
329      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
330      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
331      NULL},
333     {"query-y", 'Y',
334      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
335      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
336      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
337      NULL},
339     {"query-width", 'W',
340      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
341      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
342      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
343      NULL},
345     {"query-height", 'H',
346      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
347      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
348      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
349      NULL},
351     {"query-id", 'I',
352      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
353      N_("The ID of the object whose dimensions are queried"),
354      N_("ID")},
356     {"extension-directory", 'x',
357      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
358      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
359      N_("Print out the extension directory and exit"),
360      NULL},
362     {"slideshow", 's',
363      POPT_ARG_NONE, &sp_global_slideshow, SP_ARG_SLIDESHOW,
364      N_("Show given files one-by-one, switch to next on any key/mouse event"),
365      NULL},
367     {"vacuum-defs", 0,
368      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
369      N_("Remove unused definitions from the defs section(s) of the document"),
370      NULL},
372     {"verb-list", 0,
373      POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
374      N_("List the IDs of all the verbs in Inkscape"),
375      NULL},
377     {"verb", 0,
378      POPT_ARG_STRING, NULL, SP_ARG_VERB,
379      N_("Verb to call when Inkscape opens."),
380      N_("VERB-ID")},
382     {"select", 0,
383      POPT_ARG_STRING, NULL, SP_ARG_SELECT,
384      N_("Object ID to select when Inkscape opens."),
385      N_("OBJECT-ID")},
387     POPT_AUTOHELP POPT_TABLEEND
388 };
390 #include <ui/view/view.h>
391 #include <desktop.h>
392 #include <desktop-handles.h>
393 #include <helper/action.h>
394 #include <selection.h>
396 class CmdLineAction {
397     gint _type;
398     gchar * _arg;
400     static std::list <CmdLineAction *> _list;
402 public:
403     CmdLineAction (gint type, gchar const * arg) : _type(type), _arg(NULL) {
404         if (arg != NULL) {
405             _arg = g_strdup(arg);
406         }
408         _list.insert(_list.end(), this);
410         return;
411     }
413     ~CmdLineAction () {
414         if (_arg != NULL) {
415             g_free(_arg);
416         }
417     }
419     void doIt (Inkscape::UI::View::View * view) {
420         //printf("Doing: %s\n", _arg);
421         switch (_type) {
422             case SP_ARG_VERB: {
423                 Inkscape::Verb * verb = Inkscape::Verb::getbyid(_arg);
424                 if (verb == NULL) {
425                     printf(_("Unable to find verb ID '%s' specified on the command line.\n"), _arg);
426                     break;
427                 }
428                 SPAction * action = verb->get_action(view);
429                 sp_action_perform(action, NULL);
430                 break;
431             }
432             case SP_ARG_SELECT: {
433                 SPDesktop * desktop = dynamic_cast<SPDesktop *>(view);
434                 if (desktop == NULL) { break; }
436                 SPDocument * doc = view->doc();
437                 SPObject * obj = doc->getObjectById(_arg);
438                 if (obj == NULL) {
439                     printf("Unable to find node ID: '%s'\n", _arg);
440                     break;
441                 }
443                 Inkscape::Selection * selection = sp_desktop_selection(desktop);
444                 selection->add(obj, false);
445                 break;
446             }
447         }
448     }
450     static void doList (Inkscape::UI::View::View * view) {
451         for (std::list<CmdLineAction *>::iterator i = _list.begin();
452                 i != _list.end(); i++) {
453             CmdLineAction * entry = *i;
454             entry->doIt(view);
455         }
456     }
458     static bool idle (void) {
459         std::list<SPDesktop *> desktops;
460         inkscape_get_all_desktops(desktops);
462         // We're going to assume one desktop per document, because no one
463         // should have had time to make more at this point.
464         for (std::list<SPDesktop *>::iterator i = desktops.begin();
465                 i != desktops.end(); i++) {
466             SPDesktop * desktop = *i;
467             //Inkscape::UI::View::View * view = dynamic_cast<Inkscape::UI::View::View *>(desktop);
468             doList(desktop);
469         }
470         return false;
471     }
472 };
473 std::list <CmdLineAction *> CmdLineAction::_list;
476 static bool needToRecodeParams = true;
477 gchar* blankParam = "";
479 int
480 main(int argc, char **argv)
482 #ifdef HAVE_FPSETMASK
483     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
484        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
485        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
486     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
487 #endif
489 #ifdef ENABLE_NLS
490 #ifdef WIN32
491     RegistryTool rt;
492     rt.setPathInfo();
493     gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
494     bindtextdomain(GETTEXT_PACKAGE, pathBuf);
495     g_free(pathBuf);
496 #else
497 #ifdef ENABLE_BINRELOC
498     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
499 #else
500     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
501 #endif
502 #endif
503     // Allow the user to override the locale directory by setting 
504     // the environment variable INKSCAPE_LOCALEDIR.
505     char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
506     if (inkscape_localedir != NULL) {
507         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
508     }
509 #endif
511     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
513 #ifdef ENABLE_NLS
514     textdomain(GETTEXT_PACKAGE);
515 #endif
517     LIBXML_TEST_VERSION
519     Inkscape::GC::init();
521     Inkscape::Debug::Logger::init();
523     gboolean use_gui;
524 #ifndef WIN32
525     use_gui = (getenv("DISPLAY") != NULL);
526 #else
527     /*
528       Set the current directory to the directory of the
529       executable.  This seems redundant, but is needed for
530       when inkscape.exe is executed from another directory.
531       We use relative paths on win32.
532       HKCR\svgfile\shell\open\command is a good example
533     */
534     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
535     char *homedir = g_path_get_dirname(argv[0]);
536     SetCurrentDirectory(homedir);
537     g_free(homedir);
539     use_gui = TRUE;
540 #endif
541     /* Test whether with/without GUI is forced */
542     for (int i = 1; i < argc; i++) {
543         if (!strcmp(argv[i], "-z")
544             || !strcmp(argv[i], "--without-gui")
545             || !strcmp(argv[i], "-p")
546             || !strncmp(argv[i], "--print", 7)
547             || !strcmp(argv[i], "-e")
548             || !strncmp(argv[i], "--export-png", 12)
549             || !strcmp(argv[i], "-l")
550             || !strncmp(argv[i], "--export-plain-svg", 12)
551             || !strcmp(argv[i], "-i")
552             || !strncmp(argv[i], "--export-area-drawing", 21)
553             || !strcmp(argv[i], "-D")
554             || !strncmp(argv[i], "--export-area-canvas", 20)
555             || !strcmp(argv[i], "-C")
556             || !strncmp(argv[i], "--export-id", 12)
557             || !strcmp(argv[i], "-P")
558             || !strncmp(argv[i], "--export-ps", 11)
559             || !strcmp(argv[i], "-E")
560             || !strncmp(argv[i], "--export-eps", 12)
561             || !strcmp(argv[i], "-A")
562             || !strncmp(argv[i], "--export-pdf", 12)
563             || !strcmp(argv[i], "-W")
564             || !strncmp(argv[i], "--query-width", 13)
565             || !strcmp(argv[i], "-H")
566             || !strncmp(argv[i], "--query-height", 14)
567             || !strcmp(argv[i], "-X")
568             || !strncmp(argv[i], "--query-x", 13)
569             || !strcmp(argv[i], "-Y")
570             || !strncmp(argv[i], "--query-y", 14)
571             || !strcmp(argv[i], "--vacuum-defs")
572            )
573         {
574             /* main_console handles any exports -- not the gui */
575             use_gui = FALSE;
576             break;
577         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
578             use_gui = TRUE;
579             break;
580         }
581     }
583 #ifdef WIN32
584 #ifndef REPLACEARGS_ANSI
585     if ( PrintWin32::is_os_wide() )
586 #endif // REPLACEARGS_ANSI
587     {
588         // If the call fails, we'll need to convert charsets
589         needToRecodeParams = !replaceArgs( argc, argv );
590     }
591 #endif // WIN32
593     /// \todo  Should this be a static object (see inkscape.cpp)?
594     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
596     return app.run();
599 void fixupSingleFilename( gchar **orig, gchar **spare )
601     if ( orig && *orig && **orig ) {
602         GError *error = NULL;
603         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
604         if ( newFileName )
605         {
606             *orig = newFileName;
607             if ( spare ) {
608                 *spare = newFileName;
609             }
610 //             g_message("Set a replacement fixup");
611         }
612     }
615 GSList *fixupFilenameEncoding( GSList* fl )
617     GSList *newFl = NULL;
618     while ( fl ) {
619         gchar *fn = static_cast<gchar*>(fl->data);
620         fl = g_slist_remove( fl, fl->data );
621         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
622         if ( newFileName ) {
624             if ( 0 )
625             {
626                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
627                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
628                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
629                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
630                 gtk_dialog_run (GTK_DIALOG (w));
631                 gtk_widget_destroy (w);
632                 g_free(safeNewFn);
633                 g_free(safeFn);
634             }
636             g_free( fn );
637             fn = newFileName;
638             newFileName = 0;
639         }
640         else
641             if ( 0 )
642         {
643             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
644             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
645             gtk_dialog_run (GTK_DIALOG (w));
646             gtk_widget_destroy (w);
647             g_free(safeFn);
648         }
649         newFl = g_slist_append( newFl, fn );
650     }
651     return newFl;
654 int sp_common_main( int argc, char const **argv, GSList **flDest )
656     /// \todo fixme: Move these to some centralized location (Lauris)
657     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
658     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
661     // temporarily switch gettext encoding to locale, so that help messages can be output properly
662     gchar const *charset;
663     g_get_charset(&charset);
665     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
667     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
668     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
669     g_return_val_if_fail(ctx != NULL, 1);
671     /* Collect own arguments */
672     GSList *fl = sp_process_args(ctx);
673     poptFreeContext(ctx);
675     // now switch gettext back to UTF-8 (for GUI)
676     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
678     // Now let's see if the file list still holds up
679     if ( needToRecodeParams )
680     {
681         fl = fixupFilenameEncoding( fl );
682     }
684     // Check the globals for filename-fixup
685     if ( needToRecodeParams )
686     {
687         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
688         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
689         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
690     }
691     else
692     {
693         if ( sp_export_png )
694             sp_export_png_utf8 = g_strdup( sp_export_png );
695         if ( sp_export_svg )
696             sp_export_svg_utf8 = g_strdup( sp_export_svg );
697         if ( sp_global_printer )
698             sp_global_printer_utf8 = g_strdup( sp_global_printer );
699     }
701     // Return the list if wanted, else free it up.
702     if ( flDest ) {
703         *flDest = fl;
704         fl = 0;
705     } else {
706         while ( fl ) {
707             g_free( fl->data );
708             fl = g_slist_remove( fl, fl->data );
709         }
710     }
711     return 0;
714 int
715 sp_main_gui(int argc, char const **argv)
717     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
719     GSList *fl = NULL;
720     int retVal = sp_common_main( argc, argv, &fl );
721     g_return_val_if_fail(retVal == 0, 1);
723     inkscape_gtk_stock_init();
725     /* Set default icon */
726     gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
727     if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
728         gtk_window_set_default_icon_from_file(filename, NULL);
729     }
730     g_free (filename);
731     filename = 0;
733     if (!sp_global_slideshow) {
734         gboolean create_new = TRUE;
736         /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
737         inkscape_application_init(argv[0], true);
739         while (fl) {
740             if (sp_file_open((gchar *)fl->data,NULL)) {
741                 create_new=FALSE;
742             }
743             fl = g_slist_remove(fl, fl->data);
744         }
745         if (create_new) {
746             sp_file_new_default();
747         }
748     } else {
749         if (fl) {
750             GtkWidget *ss;
751             /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
752             inkscape_application_init(argv[0], true);
753             ss = sp_slideshow_new(fl);
754             if (ss) gtk_widget_show(ss);
755         } else {
756             g_warning ("No slides to display");
757             exit(0);
758         }
759     }
761     Glib::signal_idle().connect(sigc::ptr_fun(&CmdLineAction::idle));
762     main_instance.run();
764 #ifdef WIN32
765     //We might not need anything here
766     //sp_win32_finish(); <-- this is a NOP func
767 #endif
769     return 0;
772 int
773 sp_main_console(int argc, char const **argv)
775     /* We are started in text mode */
777     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
778      * in a non-Gtk environment.  Used in libnrtype's
779      * FontInstance.cpp and FontFactory.cpp.
780      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
781      */
782     g_type_init();
783     char **argv2 = const_cast<char **>(argv);
784     gtk_init_check( &argc, &argv2 );
785     //setlocale(LC_ALL, "");
787     GSList *fl = NULL;
788     int retVal = sp_common_main( argc, argv, &fl );
789     g_return_val_if_fail(retVal == 0, 1);
791     if (fl == NULL) {
792         g_print("Nothing to do!\n");
793         exit(0);
794     }
796     inkscape_application_init(argv[0], false);
798     while (fl) {
799         SPDocument *doc;
801         doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
802         if (doc == NULL) {
803             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
804         }
805         if (doc == NULL) {
806             g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
807         } else {
808             if (sp_vacuum_defs) {
809                 vacuum_document(doc);
810             }
811             if (sp_vacuum_defs && !sp_export_svg) {
812                 // save under the name given in the command line
813                 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
814             }
815             if (sp_global_printer) {
816                 sp_print_document_to_file(doc, sp_global_printer);
817             }
818             if (sp_export_png || sp_export_id || sp_export_area_drawing) {
819                 sp_do_export_png(doc);
820             }
821             if (sp_export_svg) {
822                 Inkscape::XML::Document *rdoc;
823                 Inkscape::XML::Node *repr;
824                 rdoc = sp_repr_document_new("svg:svg");
825                 repr = rdoc->root();
826                 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
827                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
828             }
829             if (sp_export_ps) {
830                 do_export_ps(doc, sp_export_ps, "image/x-postscript");
831             }
832             if (sp_export_eps) {
833                 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
834             }
835             if (sp_export_pdf) {
836                 do_export_pdf(doc, sp_export_pdf, "application/pdf");
837             }
838             if (sp_query_width || sp_query_height) {
839                 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
840             } else if (sp_query_x || sp_query_y) {
841                 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
842             }
844             //CmdLineAction::doList(doc);
845         }
847         fl = g_slist_remove(fl, fl->data);
848     }
850     inkscape_unref();
852     return 0;
855 static void
856 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
858     SPObject *o = NULL;
860     if (id) {
861         o = doc->getObjectById(id);
862         if (o) {
863             if (!SP_IS_ITEM (o)) {
864                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
865                 return;
866             }
867         } else {
868             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
869             return;
870         }
871     } else {
872         o = SP_DOCUMENT_ROOT(doc);
873     }
875     if (o) {
876         sp_document_ensure_up_to_date (doc);
877         SPItem *item = ((SPItem *) o);
878         NR::Rect area = item->invokeBbox(sp_item_i2doc_affine(item)); // "true" SVG bbox for scripting
880         Inkscape::SVGOStringStream os;
881         if (extent) {
882             os << area.extent(axis);
883         } else {
884             os << area.min()[axis];
885         }
886         g_print ("%s", os.str().c_str());
887     }
891 static void
892 sp_do_export_png(SPDocument *doc)
894     const gchar *filename = NULL;
895     gdouble dpi = 0.0;
897     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
898         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
899     }
901     GSList *items = NULL;
903     NRRect area;
904     if (sp_export_id || sp_export_area_drawing) {
906         SPObject *o = NULL;
907         SPObject *o_area = NULL;
908         if (sp_export_id && sp_export_area_drawing) {
909             o = doc->getObjectById(sp_export_id);
910             o_area = SP_DOCUMENT_ROOT (doc);
911         } else if (sp_export_id) {
912             o = doc->getObjectById(sp_export_id);
913             o_area = o;
914         } else if (sp_export_area_drawing) {
915             o = SP_DOCUMENT_ROOT (doc);
916             o_area = o;
917         } 
919         if (o) {
920             if (!SP_IS_ITEM (o)) {
921                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
922                 return;
923             }
925             items = g_slist_prepend (items, SP_ITEM(o));
927             if (sp_export_id_only) {
928                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
929             }
931             if (sp_export_use_hints) {
933                 // retrieve export filename hint
934                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
935                 if (fn_hint) {
936                     if (sp_export_png) {
937                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
938                         filename = sp_export_png;
939                     } else {
940                         filename = fn_hint;
941                     }
942                 } else {
943                     g_warning ("Export filename hint not found for the object.");
944                     filename = sp_export_png;
945                 }
947                 // retrieve export dpi hints
948                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
949                 if (dpi_hint) {
950                     if (sp_export_dpi || sp_export_width || sp_export_height) {
951                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
952                     } else {
953                         dpi = atof(dpi_hint);
954                     }
955                 } else {
956                     g_warning ("Export DPI hint not found for the object.");
957                 }
959             }
961             // write object bbox to area
962             sp_document_ensure_up_to_date (doc);
963             sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
964         } else {
965             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
966             return;
967         }
968     }
969     
970     if (sp_export_area) {
971         /* Try to parse area (given in SVG pixels) */
972         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
973             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
974             return;
975         }
976         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
977             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
978             return;
979         }
980     } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
981         /* Export the whole canvas */
982         sp_document_ensure_up_to_date (doc);
983         area.x0 = SP_ROOT(doc->root)->x.computed;
984         area.y0 = SP_ROOT(doc->root)->y.computed;
985         area.x1 = area.x0 + sp_document_width (doc);
986         area.y1 = area.y0 + sp_document_height (doc);
987     }
989     // set filename and dpi from options, if not yet set from the hints
990     if (!filename) {
991         if (!sp_export_png) {
992             g_warning ("No export filename given and no filename hint. Nothing exported.");
993             return;
994         }
995         filename = sp_export_png;
996     }
998     if (sp_export_dpi && dpi == 0.0) {
999         dpi = atof(sp_export_dpi);
1000         if ((dpi < 0.1) || (dpi > 10000.0)) {
1001             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1002             return;
1003         }
1004         g_print("DPI: %g\n", dpi);
1005     }
1007     if (sp_export_area_snap) {
1008         area.x0 = std::floor (area.x0);
1009         area.y0 = std::floor (area.y0);
1010         area.x1 = std::ceil (area.x1);
1011         area.y1 = std::ceil (area.y1);
1012     }
1014     // default dpi
1015     if (dpi == 0.0)
1016         dpi = PX_PER_IN;
1018     gint width = 0;
1019     gint height = 0;
1021     if (sp_export_width) {
1022         width = atoi(sp_export_width);
1023         if ((width < 1) || (width > 65536)) {
1024             g_warning("Export width %d out of range (1 - 65536). Nothing exported.", width);
1025             return;
1026         }
1027         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1028     }
1030     if (sp_export_height) {
1031         height = atoi(sp_export_height);
1032         if ((height < 1) || (height > 65536)) {
1033             g_warning("Export height %d out of range (1 - 65536). Nothing exported.", width);
1034             return;
1035         }
1036         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1037     }
1039     if (!sp_export_width) {
1040         width = (gint) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1041     }
1043     if (!sp_export_height) {
1044         height = (gint) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1045     }
1047     guint32 bgcolor = 0x00000000;
1048     if (sp_export_background) {
1049         // override the page color
1050         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1051         bgcolor |= 0xff; // default is no opacity
1052     } else {
1053         // read from namedview
1054         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1055         if (nv && nv->attribute("pagecolor"))
1056             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1057         if (nv && nv->attribute("inkscape:pageopacity"))
1058             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1059     }
1061     if (sp_export_background_opacity) {
1062         // override opacity
1063         gfloat value;
1064         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1065             if (value > 1.0) {
1066                 value = CLAMP (value, 1.0f, 255.0f);
1067                 bgcolor &= (guint32) 0xffffff00;
1068                 bgcolor |= (guint32) floor(value);
1069             } else {
1070                 value = CLAMP (value, 0.0f, 1.0f);
1071                 bgcolor &= (guint32) 0xffffff00;
1072                 bgcolor |= SP_COLOR_F_TO_U(value);
1073             }
1074         }
1075     }
1077     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1079     g_print("Area %g:%g:%g:%g exported to %d x %d pixels (%g dpi)\n", area.x0, area.y0, area.x1, area.y1, width, height, dpi);
1081     g_print("Bitmap saved as: %s\n", filename);
1083     if ((width >= 1) && (height >= 1) && (width < 65536) && (height < 65536)) {
1084         sp_export_png_file(doc, filename, area.x0, area.y0, area.x1, area.y1, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
1085     } else {
1086         g_warning("Calculated bitmap dimensions %d %d are out of range (1 - 65535). Nothing exported.", width, height);
1087     }
1089     g_slist_free (items);
1093 /**
1094  *  Perform an export of either PS or EPS.
1095  *
1096  *  \param doc Document to export.
1097  *  \param uri URI to export to.
1098  *  \param mime MIME type to export as.
1099  */
1101 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1103     Inkscape::Extension::DB::OutputList o;
1104     Inkscape::Extension::db.get_output_list(o);
1105     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1106     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1107         i++;
1108     }
1110     if (i == o.end())
1111     {
1112         g_warning ("Could not find an extension to export this file.");
1113         return;
1114     }
1116     bool old_text_to_path = false;
1117     bool old_font_embedded = false;
1118     bool old_bbox_page = false;
1120     try {
1121         old_text_to_path = (*i)->get_param_bool("textToPath");
1122         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1123     }
1124     catch (...) {
1125         g_warning ("Could not set export-text-to-path option for this export.");
1126     }
1128     try {
1129         old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1130         (*i)->set_param_bool("fontEmbedded", sp_export_font);
1131     }
1132     catch (...) {
1133         g_warning ("Could not set export-font option for this export.");
1134     }
1136     try {
1137         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1138         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1139     }
1140     catch (...) {
1141         g_warning ("Could not set export-bbox-page option for this export.");
1142     }
1144     (*i)->save(doc, uri);
1146     try {
1147         (*i)->set_param_bool("textToPath", old_text_to_path);
1148         (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1149         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1150     }
1151     catch (...) {
1153     }
1156 /**
1157  *  Perform a PDF export
1158  *
1159  *  \param doc Document to export.
1160  *  \param uri URI to export to.
1161  *  \param mime MIME type to export as.
1162  */
1164 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1166     Inkscape::Extension::DB::OutputList o;
1167     Inkscape::Extension::db.get_output_list(o);
1168     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1169     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1170         i++;
1171     }
1173     if (i == o.end())
1174     {
1175         g_warning ("Could not find an extension to export this file.");
1176         return;
1177     }
1179     (*i)->save(doc, uri);
1182 #ifdef WIN32
1183 bool replaceArgs( int& argc, char**& argv )
1185     bool worked = false;
1187 #ifdef REPLACEARGS_DEBUG
1188     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1189 #endif // REPLACEARGS_DEBUG
1191     wchar_t* line = GetCommandLineW();
1192     if ( line )
1193     {
1194 #ifdef REPLACEARGS_DEBUG
1195         {
1196             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1197             if ( utf8Line )
1198             {
1199                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1200                 {
1201                     char tmp[strlen(safe) + 32];
1202                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1203                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1204                 }
1205             }
1206         }
1207 #endif // REPLACEARGS_DEBUG
1209         int numArgs = 0;
1210         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1212 #ifdef REPLACEARGS_ANSI
1213 // test code for trying things on Win95/98/ME
1214         if ( !parsed )
1215         {
1216 #ifdef REPLACEARGS_DEBUG
1217             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1218 #endif // REPLACEARGS_DEBUG
1219             int lineLen = wcslen(line) + 1;
1220             wchar_t* lineDup = new wchar_t[lineLen];
1221             wcsncpy( lineDup, line, lineLen );
1223             int pos = 0;
1224             bool inQuotes = false;
1225             bool inWhitespace = true;
1226             std::vector<int> places;
1227             while ( lineDup[pos] )
1228             {
1229                 if ( inQuotes )
1230                 {
1231                     if ( lineDup[pos] == L'"' )
1232                     {
1233                         inQuotes = false;
1234                     }
1235                 }
1236                 else if ( lineDup[pos] == L'"' )
1237                 {
1238                     inQuotes = true;
1239                     inWhitespace = false;
1240                     places.push_back(pos);
1241                 }
1242                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1243                 {
1244                     if ( !inWhitespace )
1245                     {
1246                         inWhitespace = true;
1247                         lineDup[pos] = 0;
1248                     }
1249                 }
1250                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1251                 {
1252                     inWhitespace = false;
1253                     places.push_back(pos);
1254                 }
1255                 else
1256                 {
1257                     // consume
1258                 }
1259                 pos++;
1260             }
1261 #ifdef REPLACEARGS_DEBUG
1262             {
1263                 char tmp[256];
1264                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1265                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1266             }
1267 #endif // REPLACEARGS_DEBUG
1269             wchar_t** block = new wchar_t*[places.size()];
1270             int i = 0;
1271             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1272             {
1273                 block[i++] = &lineDup[*it];
1274             }
1275             parsed = block;
1276             numArgs = places.size();
1277         }
1278 #endif // REPLACEARGS_ANSI
1280         if ( parsed )
1281         {
1282             std::vector<wchar_t*>expandedArgs;
1283             if ( numArgs > 0 )
1284             {
1285                 expandedArgs.push_back( parsed[0] );
1286             }
1288             for ( int i1 = 1; i1 < numArgs; i1++ )
1289             {
1290                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1291                 wildcarded &= parsed[i1][0] != L'"';
1292                 wildcarded &= parsed[i1][0] != L'-';
1293                 if ( wildcarded )
1294                 {
1295 #ifdef REPLACEARGS_ANSI
1296                     WIN32_FIND_DATAA data = {0};
1297 #else
1298                     WIN32_FIND_DATAW data = {0};
1299 #endif // REPLACEARGS_ANSI
1301                     int baseLen = wcslen(parsed[i1]) + 2;
1302                     wchar_t* base = new wchar_t[baseLen];
1303                     wcsncpy( base, parsed[i1], baseLen );
1304                     wchar_t* last = wcsrchr( base, L'\\' );
1305                     if ( last )
1306                     {
1307                         last[1] = 0;
1308                     }
1309                     else
1310                     {
1311                         base[0] = 0;
1312                     }
1313                     baseLen = wcslen( base );
1315 #ifdef REPLACEARGS_ANSI
1316                     char target[MAX_PATH];
1317                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1318                     {
1319                         HANDLE hf = FindFirstFileA( target, &data );
1320 #else
1321                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1322 #endif // REPLACEARGS_ANSI
1323                         if ( hf != INVALID_HANDLE_VALUE )
1324                         {
1325                             BOOL found = TRUE;
1326                             do
1327                             {
1328 #ifdef REPLACEARGS_ANSI
1329                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1330                                 if ( howMany > 0 )
1331                                 {
1332                                     howMany += baseLen;
1333                                     wchar_t* tmp = new wchar_t[howMany + 1];
1334                                     wcsncpy( tmp, base, howMany + 1 );
1335                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1336                                     expandedArgs.push_back( tmp );
1337                                     found = FindNextFileA( hf, &data );
1338                                 }
1339 #else
1340                                 int howMany = wcslen(data.cFileName) + baseLen;
1341                                 wchar_t* tmp = new wchar_t[howMany + 1];
1342                                 wcsncpy( tmp, base, howMany + 1 );
1343                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1344                                 expandedArgs.push_back( tmp );
1345                                 found = FindNextFileW( hf, &data );
1346 #endif // REPLACEARGS_ANSI
1347                             } while ( found );
1349                             FindClose( hf );
1350                         }
1351                         else
1352                         {
1353                             expandedArgs.push_back( parsed[i1] );
1354                         }
1355 #ifdef REPLACEARGS_ANSI
1356                     }
1357 #endif // REPLACEARGS_ANSI
1359                     delete[] base;
1360                 }
1361                 else
1362                 {
1363                     expandedArgs.push_back( parsed[i1] );
1364                 }
1365             }
1367             {
1368                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1369                 int iz = 0;
1370                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1371                 {
1372                     block[iz++] = *it;
1373                 }
1374                 parsed = block;
1375                 numArgs = expandedArgs.size();
1376             }
1378             std::vector<gchar*> newArgs;
1379             for ( int i = 0; i < numArgs; i++ )
1380             {
1381                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1382                 if ( replacement )
1383                 {
1384 #ifdef REPLACEARGS_DEBUG
1385                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1387                     if ( safe2 )
1388                     {
1389                         {
1390                             char tmp[1024];
1391                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1392                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1393                         }
1394                         g_free( safe2 );
1395                     }
1396 #endif // REPLACEARGS_DEBUG
1398                     newArgs.push_back( replacement );
1399                 }
1400                 else
1401                 {
1402                     newArgs.push_back( blankParam );
1403                 }
1404             }
1406             // Now push our munged params to be the new argv and argc
1407             {
1408                 char** block = new char*[newArgs.size()];
1409                 int iz = 0;
1410                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1411                 {
1412                     block[iz++] = *it;
1413                 }
1414                 argv = block;
1415                 argc = newArgs.size();
1416                 worked = true;
1417             }
1418         }
1419 #ifdef REPLACEARGS_DEBUG
1420         else
1421         {
1422             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1423         }
1424 #endif // REPLACEARGS_DEBUG
1425     }
1426 #ifdef REPLACEARGS_DEBUG
1427     else
1428     {
1429         {
1430             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1431         }
1433         char* line2 = GetCommandLineA();
1434         if ( line2 )
1435         {
1436             gchar *safe = Inkscape::IO::sanitizeString(line2);
1437             {
1438                 {
1439                     char tmp[strlen(safe) + 32];
1440                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1441                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1442                 }
1443             }
1444         }
1445         else
1446         {
1447             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1448         }
1449     }
1450 #endif // REPLACEARGS_DEBUG
1452     return worked;
1454 #endif // WIN32
1456 static GSList *
1457 sp_process_args(poptContext ctx)
1459     GSList *fl = NULL;
1461     gint a;
1462     while ((a = poptGetNextOpt(ctx)) >= 0) {
1463         switch (a) {
1464             case SP_ARG_FILE: {
1465                 gchar const *fn = poptGetOptArg(ctx);
1466                 if (fn != NULL) {
1467                     fl = g_slist_append(fl, g_strdup(fn));
1468                 }
1469                 break;
1470             }
1471             case SP_ARG_VERSION: {
1472                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1473                 exit(0);
1474                 break;
1475             }
1476             case SP_ARG_EXTENSIONDIR: {
1477                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1478                 exit(0);
1479                 break;
1480             }
1481             case SP_ARG_VERB_LIST: {
1482                 // This really shouldn't go here, we should init the app.
1483                 // But, since we're just exiting in this path, there is
1484                 // no harm, and this is really a better place to put
1485                 // everything else.
1486                 Inkscape::Extension::init();
1487                 Inkscape::Verb::list();
1488                 exit(0);
1489                 break;
1490             }
1491             case SP_ARG_VERB:
1492             case SP_ARG_SELECT: {
1493                 gchar const *arg = poptGetOptArg(ctx);
1494                 if (arg != NULL) {
1495                     // printf("Adding in: %s\n", arg);
1496                     new CmdLineAction(a, arg);
1497                 }
1498                 break;
1499             }
1500             default: {
1501                 break;
1502             }
1503         }
1504     }
1506     gchar const ** const args = poptGetArgs(ctx);
1507     if (args != NULL) {
1508         for (unsigned i = 0; args[i] != NULL; i++) {
1509             fl = g_slist_append(fl, g_strdup(args[i]));
1510         }
1511     }
1513     return fl;
1517 /*
1518   Local Variables:
1519   mode:c++
1520   c-file-style:"stroustrup"
1521   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1522   indent-tabs-mode:nil
1523   fill-column:99
1524   End:
1525 */
1526 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :