Code

9a6dc0b769394094d51199566c4528657f8eccd9
[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 <helper/action.h>
394 class CmdLineAction {
395     gint _type;
396     gchar * _arg;
398     static std::list <CmdLineAction *> _list;
400 public:
401     CmdLineAction (gint type, gchar const * arg) : _type(type), _arg(NULL) {
402         if (arg != NULL) {
403             _arg = g_strdup(arg);
404         }
406         _list.insert(_list.end(), this);
408         return;
409     }
411     ~CmdLineAction () {
412         if (_arg != NULL) {
413             g_free(_arg);
414         }
415     }
417     void doIt (Inkscape::UI::View::View * view) {
418         printf("Doing: %s\n", _arg);
419         switch (_type) {
420             case SP_ARG_VERB: {
421                 Inkscape::Verb * verb = Inkscape::Verb::getbyid(_arg);
422                 if (verb == NULL) {
423                     printf(_("Unable to find verb ID '%s' specified on the command line.\n"), _arg);
424                 }
425                 SPAction * action = verb->get_action(view);
426                 sp_action_perform(action, NULL);
427                 break;
428             }
429             case SP_ARG_SELECT: {
431                 break;
432             }
433         }
434     }
436     static void doList (Inkscape::UI::View::View * view) {
437         for (std::list<CmdLineAction *>::iterator i = _list.begin();
438                 i != _list.end(); i++) {
439             CmdLineAction * entry = *i;
440             entry->doIt(view);
441         }
442     }
444     static bool idle (void) {
445         std::list<SPDesktop *> desktops;
446         inkscape_get_all_desktops(desktops);
448         // We're going to assume one desktop per document, because no one
449         // should have had time to make more at this point.
450         for (std::list<SPDesktop *>::iterator i = desktops.begin();
451                 i != desktops.end(); i++) {
452             SPDesktop * desktop = *i;
453             //Inkscape::UI::View::View * view = dynamic_cast<Inkscape::UI::View::View *>(desktop);
454             doList(desktop);
455         }
456         return false;
457     }
458 };
459 std::list <CmdLineAction *> CmdLineAction::_list;
462 static bool needToRecodeParams = true;
463 gchar* blankParam = "";
465 int
466 main(int argc, char **argv)
468 #ifdef HAVE_FPSETMASK
469     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
470        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
471        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
472     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
473 #endif
475 #ifdef ENABLE_NLS
476 #ifdef WIN32
477     RegistryTool rt;
478     rt.setPathInfo();
479     gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
480     bindtextdomain(GETTEXT_PACKAGE, pathBuf);
481     g_free(pathBuf);
482 #else
483 #ifdef ENABLE_BINRELOC
484     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
485 #else
486     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
487 #endif
488 #endif
489     // Allow the user to override the locale directory by setting 
490     // the environment variable INKSCAPE_LOCALEDIR.
491     char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
492     if (inkscape_localedir != NULL) {
493         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
494     }
495 #endif
497     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
499 #ifdef ENABLE_NLS
500     textdomain(GETTEXT_PACKAGE);
501 #endif
503     LIBXML_TEST_VERSION
505     Inkscape::GC::init();
507     Inkscape::Debug::Logger::init();
509     gboolean use_gui;
510 #ifndef WIN32
511     use_gui = (getenv("DISPLAY") != NULL);
512 #else
513     /*
514       Set the current directory to the directory of the
515       executable.  This seems redundant, but is needed for
516       when inkscape.exe is executed from another directory.
517       We use relative paths on win32.
518       HKCR\svgfile\shell\open\command is a good example
519     */
520     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
521     char *homedir = g_path_get_dirname(argv[0]);
522     SetCurrentDirectory(homedir);
523     g_free(homedir);
525     use_gui = TRUE;
526 #endif
527     /* Test whether with/without GUI is forced */
528     for (int i = 1; i < argc; i++) {
529         if (!strcmp(argv[i], "-z")
530             || !strcmp(argv[i], "--without-gui")
531             || !strcmp(argv[i], "-p")
532             || !strncmp(argv[i], "--print", 7)
533             || !strcmp(argv[i], "-e")
534             || !strncmp(argv[i], "--export-png", 12)
535             || !strcmp(argv[i], "-l")
536             || !strncmp(argv[i], "--export-plain-svg", 12)
537             || !strcmp(argv[i], "-i")
538             || !strncmp(argv[i], "--export-area-drawing", 21)
539             || !strcmp(argv[i], "-D")
540             || !strncmp(argv[i], "--export-area-canvas", 20)
541             || !strcmp(argv[i], "-C")
542             || !strncmp(argv[i], "--export-id", 12)
543             || !strcmp(argv[i], "-P")
544             || !strncmp(argv[i], "--export-ps", 11)
545             || !strcmp(argv[i], "-E")
546             || !strncmp(argv[i], "--export-eps", 12)
547             || !strcmp(argv[i], "-A")
548             || !strncmp(argv[i], "--export-pdf", 12)
549             || !strcmp(argv[i], "-W")
550             || !strncmp(argv[i], "--query-width", 13)
551             || !strcmp(argv[i], "-H")
552             || !strncmp(argv[i], "--query-height", 14)
553             || !strcmp(argv[i], "-X")
554             || !strncmp(argv[i], "--query-x", 13)
555             || !strcmp(argv[i], "-Y")
556             || !strncmp(argv[i], "--query-y", 14)
557             || !strcmp(argv[i], "--vacuum-defs")
558            )
559         {
560             /* main_console handles any exports -- not the gui */
561             use_gui = FALSE;
562             break;
563         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
564             use_gui = TRUE;
565             break;
566         }
567     }
569 #ifdef WIN32
570 #ifndef REPLACEARGS_ANSI
571     if ( PrintWin32::is_os_wide() )
572 #endif // REPLACEARGS_ANSI
573     {
574         // If the call fails, we'll need to convert charsets
575         needToRecodeParams = !replaceArgs( argc, argv );
576     }
577 #endif // WIN32
579     /// \todo  Should this be a static object (see inkscape.cpp)?
580     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
582     return app.run();
585 void fixupSingleFilename( gchar **orig, gchar **spare )
587     if ( orig && *orig && **orig ) {
588         GError *error = NULL;
589         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
590         if ( newFileName )
591         {
592             *orig = newFileName;
593             if ( spare ) {
594                 *spare = newFileName;
595             }
596 //             g_message("Set a replacement fixup");
597         }
598     }
601 GSList *fixupFilenameEncoding( GSList* fl )
603     GSList *newFl = NULL;
604     while ( fl ) {
605         gchar *fn = static_cast<gchar*>(fl->data);
606         fl = g_slist_remove( fl, fl->data );
607         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
608         if ( newFileName ) {
610             if ( 0 )
611             {
612                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
613                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
614                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
615                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
616                 gtk_dialog_run (GTK_DIALOG (w));
617                 gtk_widget_destroy (w);
618                 g_free(safeNewFn);
619                 g_free(safeFn);
620             }
622             g_free( fn );
623             fn = newFileName;
624             newFileName = 0;
625         }
626         else
627             if ( 0 )
628         {
629             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
630             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
631             gtk_dialog_run (GTK_DIALOG (w));
632             gtk_widget_destroy (w);
633             g_free(safeFn);
634         }
635         newFl = g_slist_append( newFl, fn );
636     }
637     return newFl;
640 int sp_common_main( int argc, char const **argv, GSList **flDest )
642     /// \todo fixme: Move these to some centralized location (Lauris)
643     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
644     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
647     // temporarily switch gettext encoding to locale, so that help messages can be output properly
648     gchar const *charset;
649     g_get_charset(&charset);
651     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
653     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
654     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
655     g_return_val_if_fail(ctx != NULL, 1);
657     /* Collect own arguments */
658     GSList *fl = sp_process_args(ctx);
659     poptFreeContext(ctx);
661     // now switch gettext back to UTF-8 (for GUI)
662     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
664     // Now let's see if the file list still holds up
665     if ( needToRecodeParams )
666     {
667         fl = fixupFilenameEncoding( fl );
668     }
670     // Check the globals for filename-fixup
671     if ( needToRecodeParams )
672     {
673         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
674         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
675         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
676     }
677     else
678     {
679         if ( sp_export_png )
680             sp_export_png_utf8 = g_strdup( sp_export_png );
681         if ( sp_export_svg )
682             sp_export_svg_utf8 = g_strdup( sp_export_svg );
683         if ( sp_global_printer )
684             sp_global_printer_utf8 = g_strdup( sp_global_printer );
685     }
687     // Return the list if wanted, else free it up.
688     if ( flDest ) {
689         *flDest = fl;
690         fl = 0;
691     } else {
692         while ( fl ) {
693             g_free( fl->data );
694             fl = g_slist_remove( fl, fl->data );
695         }
696     }
697     return 0;
700 int
701 sp_main_gui(int argc, char const **argv)
703     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
705     GSList *fl = NULL;
706     int retVal = sp_common_main( argc, argv, &fl );
707     g_return_val_if_fail(retVal == 0, 1);
709     inkscape_gtk_stock_init();
711     /* Set default icon */
712     gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
713     if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
714         gtk_window_set_default_icon_from_file(filename, NULL);
715     }
716     g_free (filename);
717     filename = 0;
719     if (!sp_global_slideshow) {
720         gboolean create_new = TRUE;
722         /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
723         inkscape_application_init(argv[0], true);
725         while (fl) {
726             if (sp_file_open((gchar *)fl->data,NULL)) {
727                 create_new=FALSE;
728             }
729             fl = g_slist_remove(fl, fl->data);
730         }
731         if (create_new) {
732             sp_file_new_default();
733         }
734     } else {
735         if (fl) {
736             GtkWidget *ss;
737             /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
738             inkscape_application_init(argv[0], true);
739             ss = sp_slideshow_new(fl);
740             if (ss) gtk_widget_show(ss);
741         } else {
742             g_warning ("No slides to display");
743             exit(0);
744         }
745     }
747     Glib::signal_idle().connect(sigc::ptr_fun(&CmdLineAction::idle));
748     main_instance.run();
750 #ifdef WIN32
751     //We might not need anything here
752     //sp_win32_finish(); <-- this is a NOP func
753 #endif
755     return 0;
758 int
759 sp_main_console(int argc, char const **argv)
761     /* We are started in text mode */
763     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
764      * in a non-Gtk environment.  Used in libnrtype's
765      * FontInstance.cpp and FontFactory.cpp.
766      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
767      */
768     g_type_init();
769     char **argv2 = const_cast<char **>(argv);
770     gtk_init_check( &argc, &argv2 );
771     //setlocale(LC_ALL, "");
773     GSList *fl = NULL;
774     int retVal = sp_common_main( argc, argv, &fl );
775     g_return_val_if_fail(retVal == 0, 1);
777     if (fl == NULL) {
778         g_print("Nothing to do!\n");
779         exit(0);
780     }
782     inkscape_application_init(argv[0], false);
784     while (fl) {
785         SPDocument *doc;
787         doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
788         if (doc == NULL) {
789             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
790         }
791         if (doc == NULL) {
792             g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
793         } else {
794             if (sp_vacuum_defs) {
795                 vacuum_document(doc);
796             }
797             if (sp_vacuum_defs && !sp_export_svg) {
798                 // save under the name given in the command line
799                 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
800             }
801             if (sp_global_printer) {
802                 sp_print_document_to_file(doc, sp_global_printer);
803             }
804             if (sp_export_png || sp_export_id || sp_export_area_drawing) {
805                 sp_do_export_png(doc);
806             }
807             if (sp_export_svg) {
808                 Inkscape::XML::Document *rdoc;
809                 Inkscape::XML::Node *repr;
810                 rdoc = sp_repr_document_new("svg:svg");
811                 repr = rdoc->root();
812                 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
813                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
814             }
815             if (sp_export_ps) {
816                 do_export_ps(doc, sp_export_ps, "image/x-postscript");
817             }
818             if (sp_export_eps) {
819                 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
820             }
821             if (sp_export_pdf) {
822                 do_export_pdf(doc, sp_export_pdf, "application/pdf");
823             }
824             if (sp_query_width || sp_query_height) {
825                 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
826             } else if (sp_query_x || sp_query_y) {
827                 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
828             }
830             //CmdLineAction::doList(doc);
831         }
833         fl = g_slist_remove(fl, fl->data);
834     }
836     inkscape_unref();
838     return 0;
841 static void
842 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
844     SPObject *o = NULL;
846     if (id) {
847         o = doc->getObjectById(id);
848         if (o) {
849             if (!SP_IS_ITEM (o)) {
850                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
851                 return;
852             }
853         } else {
854             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
855             return;
856         }
857     } else {
858         o = SP_DOCUMENT_ROOT(doc);
859     }
861     if (o) {
862         sp_document_ensure_up_to_date (doc);
863         SPItem *item = ((SPItem *) o);
864         NR::Rect area = item->invokeBbox(sp_item_i2doc_affine(item)); // "true" SVG bbox for scripting
866         Inkscape::SVGOStringStream os;
867         if (extent) {
868             os << area.extent(axis);
869         } else {
870             os << area.min()[axis];
871         }
872         g_print ("%s", os.str().c_str());
873     }
877 static void
878 sp_do_export_png(SPDocument *doc)
880     const gchar *filename = NULL;
881     gdouble dpi = 0.0;
883     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
884         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
885     }
887     GSList *items = NULL;
889     NRRect area;
890     if (sp_export_id || sp_export_area_drawing) {
892         SPObject *o = NULL;
893         SPObject *o_area = NULL;
894         if (sp_export_id && sp_export_area_drawing) {
895             o = doc->getObjectById(sp_export_id);
896             o_area = SP_DOCUMENT_ROOT (doc);
897         } else if (sp_export_id) {
898             o = doc->getObjectById(sp_export_id);
899             o_area = o;
900         } else if (sp_export_area_drawing) {
901             o = SP_DOCUMENT_ROOT (doc);
902             o_area = o;
903         } 
905         if (o) {
906             if (!SP_IS_ITEM (o)) {
907                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
908                 return;
909             }
911             items = g_slist_prepend (items, SP_ITEM(o));
913             if (sp_export_id_only) {
914                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
915             }
917             if (sp_export_use_hints) {
919                 // retrieve export filename hint
920                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
921                 if (fn_hint) {
922                     if (sp_export_png) {
923                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
924                         filename = sp_export_png;
925                     } else {
926                         filename = fn_hint;
927                     }
928                 } else {
929                     g_warning ("Export filename hint not found for the object.");
930                     filename = sp_export_png;
931                 }
933                 // retrieve export dpi hints
934                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
935                 if (dpi_hint) {
936                     if (sp_export_dpi || sp_export_width || sp_export_height) {
937                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
938                     } else {
939                         dpi = atof(dpi_hint);
940                     }
941                 } else {
942                     g_warning ("Export DPI hint not found for the object.");
943                 }
945             }
947             // write object bbox to area
948             sp_document_ensure_up_to_date (doc);
949             sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
950         } else {
951             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
952             return;
953         }
954     }
955     
956     if (sp_export_area) {
957         /* Try to parse area (given in SVG pixels) */
958         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
959             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
960             return;
961         }
962         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
963             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
964             return;
965         }
966     } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
967         /* Export the whole canvas */
968         sp_document_ensure_up_to_date (doc);
969         area.x0 = SP_ROOT(doc->root)->x.computed;
970         area.y0 = SP_ROOT(doc->root)->y.computed;
971         area.x1 = area.x0 + sp_document_width (doc);
972         area.y1 = area.y0 + sp_document_height (doc);
973     }
975     // set filename and dpi from options, if not yet set from the hints
976     if (!filename) {
977         if (!sp_export_png) {
978             g_warning ("No export filename given and no filename hint. Nothing exported.");
979             return;
980         }
981         filename = sp_export_png;
982     }
984     if (sp_export_dpi && dpi == 0.0) {
985         dpi = atof(sp_export_dpi);
986         if ((dpi < 0.1) || (dpi > 10000.0)) {
987             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
988             return;
989         }
990         g_print("DPI: %g\n", dpi);
991     }
993     if (sp_export_area_snap) {
994         area.x0 = std::floor (area.x0);
995         area.y0 = std::floor (area.y0);
996         area.x1 = std::ceil (area.x1);
997         area.y1 = std::ceil (area.y1);
998     }
1000     // default dpi
1001     if (dpi == 0.0)
1002         dpi = PX_PER_IN;
1004     gint width = 0;
1005     gint height = 0;
1007     if (sp_export_width) {
1008         width = atoi(sp_export_width);
1009         if ((width < 1) || (width > 65536)) {
1010             g_warning("Export width %d out of range (1 - 65536). Nothing exported.", width);
1011             return;
1012         }
1013         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1014     }
1016     if (sp_export_height) {
1017         height = atoi(sp_export_height);
1018         if ((height < 1) || (height > 65536)) {
1019             g_warning("Export height %d out of range (1 - 65536). Nothing exported.", width);
1020             return;
1021         }
1022         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1023     }
1025     if (!sp_export_width) {
1026         width = (gint) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1027     }
1029     if (!sp_export_height) {
1030         height = (gint) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1031     }
1033     guint32 bgcolor = 0x00000000;
1034     if (sp_export_background) {
1035         // override the page color
1036         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1037         bgcolor |= 0xff; // default is no opacity
1038     } else {
1039         // read from namedview
1040         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1041         if (nv && nv->attribute("pagecolor"))
1042             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1043         if (nv && nv->attribute("inkscape:pageopacity"))
1044             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1045     }
1047     if (sp_export_background_opacity) {
1048         // override opacity
1049         gfloat value;
1050         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1051             if (value > 1.0) {
1052                 value = CLAMP (value, 1.0f, 255.0f);
1053                 bgcolor &= (guint32) 0xffffff00;
1054                 bgcolor |= (guint32) floor(value);
1055             } else {
1056                 value = CLAMP (value, 0.0f, 1.0f);
1057                 bgcolor &= (guint32) 0xffffff00;
1058                 bgcolor |= SP_COLOR_F_TO_U(value);
1059             }
1060         }
1061     }
1063     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1065     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);
1067     g_print("Bitmap saved as: %s\n", filename);
1069     if ((width >= 1) && (height >= 1) && (width < 65536) && (height < 65536)) {
1070         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);
1071     } else {
1072         g_warning("Calculated bitmap dimensions %d %d are out of range (1 - 65535). Nothing exported.", width, height);
1073     }
1075     g_slist_free (items);
1079 /**
1080  *  Perform an export of either PS or EPS.
1081  *
1082  *  \param doc Document to export.
1083  *  \param uri URI to export to.
1084  *  \param mime MIME type to export as.
1085  */
1087 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1089     Inkscape::Extension::DB::OutputList o;
1090     Inkscape::Extension::db.get_output_list(o);
1091     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1092     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1093         i++;
1094     }
1096     if (i == o.end())
1097     {
1098         g_warning ("Could not find an extension to export this file.");
1099         return;
1100     }
1102     bool old_text_to_path = false;
1103     bool old_font_embedded = false;
1104     bool old_bbox_page = false;
1106     try {
1107         old_text_to_path = (*i)->get_param_bool("textToPath");
1108         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1109     }
1110     catch (...) {
1111         g_warning ("Could not set export-text-to-path option for this export.");
1112     }
1114     try {
1115         old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1116         (*i)->set_param_bool("fontEmbedded", sp_export_font);
1117     }
1118     catch (...) {
1119         g_warning ("Could not set export-font option for this export.");
1120     }
1122     try {
1123         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1124         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1125     }
1126     catch (...) {
1127         g_warning ("Could not set export-bbox-page option for this export.");
1128     }
1130     (*i)->save(doc, uri);
1132     try {
1133         (*i)->set_param_bool("textToPath", old_text_to_path);
1134         (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1135         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1136     }
1137     catch (...) {
1139     }
1142 /**
1143  *  Perform a PDF export
1144  *
1145  *  \param doc Document to export.
1146  *  \param uri URI to export to.
1147  *  \param mime MIME type to export as.
1148  */
1150 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1152     Inkscape::Extension::DB::OutputList o;
1153     Inkscape::Extension::db.get_output_list(o);
1154     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1155     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1156         i++;
1157     }
1159     if (i == o.end())
1160     {
1161         g_warning ("Could not find an extension to export this file.");
1162         return;
1163     }
1165     (*i)->save(doc, uri);
1168 #ifdef WIN32
1169 bool replaceArgs( int& argc, char**& argv )
1171     bool worked = false;
1173 #ifdef REPLACEARGS_DEBUG
1174     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1175 #endif // REPLACEARGS_DEBUG
1177     wchar_t* line = GetCommandLineW();
1178     if ( line )
1179     {
1180 #ifdef REPLACEARGS_DEBUG
1181         {
1182             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1183             if ( utf8Line )
1184             {
1185                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1186                 {
1187                     char tmp[strlen(safe) + 32];
1188                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1189                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1190                 }
1191             }
1192         }
1193 #endif // REPLACEARGS_DEBUG
1195         int numArgs = 0;
1196         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1198 #ifdef REPLACEARGS_ANSI
1199 // test code for trying things on Win95/98/ME
1200         if ( !parsed )
1201         {
1202 #ifdef REPLACEARGS_DEBUG
1203             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1204 #endif // REPLACEARGS_DEBUG
1205             int lineLen = wcslen(line) + 1;
1206             wchar_t* lineDup = new wchar_t[lineLen];
1207             wcsncpy( lineDup, line, lineLen );
1209             int pos = 0;
1210             bool inQuotes = false;
1211             bool inWhitespace = true;
1212             std::vector<int> places;
1213             while ( lineDup[pos] )
1214             {
1215                 if ( inQuotes )
1216                 {
1217                     if ( lineDup[pos] == L'"' )
1218                     {
1219                         inQuotes = false;
1220                     }
1221                 }
1222                 else if ( lineDup[pos] == L'"' )
1223                 {
1224                     inQuotes = true;
1225                     inWhitespace = false;
1226                     places.push_back(pos);
1227                 }
1228                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1229                 {
1230                     if ( !inWhitespace )
1231                     {
1232                         inWhitespace = true;
1233                         lineDup[pos] = 0;
1234                     }
1235                 }
1236                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1237                 {
1238                     inWhitespace = false;
1239                     places.push_back(pos);
1240                 }
1241                 else
1242                 {
1243                     // consume
1244                 }
1245                 pos++;
1246             }
1247 #ifdef REPLACEARGS_DEBUG
1248             {
1249                 char tmp[256];
1250                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1251                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1252             }
1253 #endif // REPLACEARGS_DEBUG
1255             wchar_t** block = new wchar_t*[places.size()];
1256             int i = 0;
1257             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1258             {
1259                 block[i++] = &lineDup[*it];
1260             }
1261             parsed = block;
1262             numArgs = places.size();
1263         }
1264 #endif // REPLACEARGS_ANSI
1266         if ( parsed )
1267         {
1268             std::vector<wchar_t*>expandedArgs;
1269             if ( numArgs > 0 )
1270             {
1271                 expandedArgs.push_back( parsed[0] );
1272             }
1274             for ( int i1 = 1; i1 < numArgs; i1++ )
1275             {
1276                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1277                 wildcarded &= parsed[i1][0] != L'"';
1278                 wildcarded &= parsed[i1][0] != L'-';
1279                 if ( wildcarded )
1280                 {
1281 #ifdef REPLACEARGS_ANSI
1282                     WIN32_FIND_DATAA data = {0};
1283 #else
1284                     WIN32_FIND_DATAW data = {0};
1285 #endif // REPLACEARGS_ANSI
1287                     int baseLen = wcslen(parsed[i1]) + 2;
1288                     wchar_t* base = new wchar_t[baseLen];
1289                     wcsncpy( base, parsed[i1], baseLen );
1290                     wchar_t* last = wcsrchr( base, L'\\' );
1291                     if ( last )
1292                     {
1293                         last[1] = 0;
1294                     }
1295                     else
1296                     {
1297                         base[0] = 0;
1298                     }
1299                     baseLen = wcslen( base );
1301 #ifdef REPLACEARGS_ANSI
1302                     char target[MAX_PATH];
1303                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1304                     {
1305                         HANDLE hf = FindFirstFileA( target, &data );
1306 #else
1307                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1308 #endif // REPLACEARGS_ANSI
1309                         if ( hf != INVALID_HANDLE_VALUE )
1310                         {
1311                             BOOL found = TRUE;
1312                             do
1313                             {
1314 #ifdef REPLACEARGS_ANSI
1315                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1316                                 if ( howMany > 0 )
1317                                 {
1318                                     howMany += baseLen;
1319                                     wchar_t* tmp = new wchar_t[howMany + 1];
1320                                     wcsncpy( tmp, base, howMany + 1 );
1321                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1322                                     expandedArgs.push_back( tmp );
1323                                     found = FindNextFileA( hf, &data );
1324                                 }
1325 #else
1326                                 int howMany = wcslen(data.cFileName) + baseLen;
1327                                 wchar_t* tmp = new wchar_t[howMany + 1];
1328                                 wcsncpy( tmp, base, howMany + 1 );
1329                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1330                                 expandedArgs.push_back( tmp );
1331                                 found = FindNextFileW( hf, &data );
1332 #endif // REPLACEARGS_ANSI
1333                             } while ( found );
1335                             FindClose( hf );
1336                         }
1337                         else
1338                         {
1339                             expandedArgs.push_back( parsed[i1] );
1340                         }
1341 #ifdef REPLACEARGS_ANSI
1342                     }
1343 #endif // REPLACEARGS_ANSI
1345                     delete[] base;
1346                 }
1347                 else
1348                 {
1349                     expandedArgs.push_back( parsed[i1] );
1350                 }
1351             }
1353             {
1354                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1355                 int iz = 0;
1356                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1357                 {
1358                     block[iz++] = *it;
1359                 }
1360                 parsed = block;
1361                 numArgs = expandedArgs.size();
1362             }
1364             std::vector<gchar*> newArgs;
1365             for ( int i = 0; i < numArgs; i++ )
1366             {
1367                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1368                 if ( replacement )
1369                 {
1370 #ifdef REPLACEARGS_DEBUG
1371                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1373                     if ( safe2 )
1374                     {
1375                         {
1376                             char tmp[1024];
1377                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1378                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1379                         }
1380                         g_free( safe2 );
1381                     }
1382 #endif // REPLACEARGS_DEBUG
1384                     newArgs.push_back( replacement );
1385                 }
1386                 else
1387                 {
1388                     newArgs.push_back( blankParam );
1389                 }
1390             }
1392             // Now push our munged params to be the new argv and argc
1393             {
1394                 char** block = new char*[newArgs.size()];
1395                 int iz = 0;
1396                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1397                 {
1398                     block[iz++] = *it;
1399                 }
1400                 argv = block;
1401                 argc = newArgs.size();
1402                 worked = true;
1403             }
1404         }
1405 #ifdef REPLACEARGS_DEBUG
1406         else
1407         {
1408             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1409         }
1410 #endif // REPLACEARGS_DEBUG
1411     }
1412 #ifdef REPLACEARGS_DEBUG
1413     else
1414     {
1415         {
1416             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1417         }
1419         char* line2 = GetCommandLineA();
1420         if ( line2 )
1421         {
1422             gchar *safe = Inkscape::IO::sanitizeString(line2);
1423             {
1424                 {
1425                     char tmp[strlen(safe) + 32];
1426                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1427                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1428                 }
1429             }
1430         }
1431         else
1432         {
1433             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1434         }
1435     }
1436 #endif // REPLACEARGS_DEBUG
1438     return worked;
1440 #endif // WIN32
1442 static GSList *
1443 sp_process_args(poptContext ctx)
1445     GSList *fl = NULL;
1447     gint a;
1448     while ((a = poptGetNextOpt(ctx)) >= 0) {
1449         switch (a) {
1450             case SP_ARG_FILE: {
1451                 gchar const *fn = poptGetOptArg(ctx);
1452                 if (fn != NULL) {
1453                     fl = g_slist_append(fl, g_strdup(fn));
1454                 }
1455                 break;
1456             }
1457             case SP_ARG_VERSION: {
1458                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1459                 exit(0);
1460                 break;
1461             }
1462             case SP_ARG_EXTENSIONDIR: {
1463                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1464                 exit(0);
1465                 break;
1466             }
1467             case SP_ARG_VERB_LIST: {
1468                 // This really shouldn't go here, we should init the app.
1469                 // But, since we're just exiting in this path, there is
1470                 // no harm, and this is really a better place to put
1471                 // everything else.
1472                 Inkscape::Extension::init();
1473                 Inkscape::Verb::list();
1474                 exit(0);
1475                 break;
1476             }
1477             case SP_ARG_VERB:
1478             case SP_ARG_SELECT: {
1479                 gchar const *arg = poptGetOptArg(ctx);
1480                 if (arg != NULL) {
1481                     // printf("Adding in: %s\n", arg);
1482                     new CmdLineAction(a, arg);
1483                 }
1484                 break;
1485             }
1486             default: {
1487                 break;
1488             }
1489         }
1490     }
1492     gchar const ** const args = poptGetArgs(ctx);
1493     if (args != NULL) {
1494         for (unsigned i = 0; args[i] != NULL; i++) {
1495             fl = g_slist_append(fl, g_strdup(args[i]));
1496         }
1497     }
1499     return fl;
1503 /*
1504   Local Variables:
1505   mode:c++
1506   c-file-style:"stroustrup"
1507   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1508   indent-tabs-mode:nil
1509   fill-column:99
1510   End:
1511 */
1512 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :