Code

Applying fixes for gcc 4.3 build issues (closes LP: #169115)
[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 <cstring>
37 #include <string>
38 #include <locale.h>
40 #include <popt.h>
41 #ifndef POPT_TABLEEND
42 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
43 #endif /* Not def: POPT_TABLEEND */
45 #include <libxml/tree.h>
46 #include <glib-object.h>
47 #include <gtk/gtkmain.h>
48 #include <gtk/gtksignal.h>
49 #include <gtk/gtkwindow.h>
50 #include <gtk/gtkbox.h>
52 #include "gc-core.h"
54 #include "macros.h"
55 #include "file.h"
56 #include "document.h"
57 #include "sp-object.h"
58 #include "interface.h"
59 #include "print.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"
81 #include "debug/log-display-config.h"
83 #include "helper/png-write.h"
85 #include <extension/extension.h>
86 #include <extension/system.h>
87 #include <extension/db.h>
88 #include <extension/output.h>
90 #ifdef WIN32
91 //#define REPLACEARGS_ANSI
92 //#define REPLACEARGS_DEBUG
94 #include "registrytool.h"
96 #include "extension/internal/win32.h"
97 using Inkscape::Extension::Internal::PrintWin32;
99 #endif // WIN32
101 #include "extension/init.h"
103 #include <glibmm/i18n.h>
104 #include <gtkmm/main.h>
106 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
107 #define bind_textdomain_codeset(p,c)
108 #endif
110 #include "application/application.h"
112 #include "main-cmdlineact.h"
114 #include <png.h>
115 #include <errno.h>
117 enum {
118     SP_ARG_NONE,
119     SP_ARG_NOGUI,
120     SP_ARG_GUI,
121     SP_ARG_FILE,
122     SP_ARG_PRINT,
123     SP_ARG_EXPORT_PNG,
124     SP_ARG_EXPORT_DPI,
125     SP_ARG_EXPORT_AREA,
126     SP_ARG_EXPORT_AREA_DRAWING,
127     SP_ARG_EXPORT_AREA_CANVAS,
128     SP_ARG_EXPORT_AREA_SNAP,
129     SP_ARG_EXPORT_WIDTH,
130     SP_ARG_EXPORT_HEIGHT,
131     SP_ARG_EXPORT_ID,
132     SP_ARG_EXPORT_ID_ONLY,
133     SP_ARG_EXPORT_USE_HINTS,
134     SP_ARG_EXPORT_BACKGROUND,
135     SP_ARG_EXPORT_BACKGROUND_OPACITY,
136     SP_ARG_EXPORT_SVG,
137     SP_ARG_EXPORT_PS,
138     SP_ARG_EXPORT_EPS,
139     SP_ARG_EXPORT_PDF,
140 #ifdef WIN32
141     SP_ARG_EXPORT_EMF,
142 #endif //WIN32
143     SP_ARG_EXPORT_TEXT_TO_PATH,
144     SP_ARG_EXPORT_FONT,
145     SP_ARG_EXPORT_BBOX_PAGE,
146     SP_ARG_EXTENSIONDIR,
147     SP_ARG_FIT_PAGE_TO_DRAWING,
148     SP_ARG_QUERY_X,
149     SP_ARG_QUERY_Y,
150     SP_ARG_QUERY_WIDTH,
151     SP_ARG_QUERY_HEIGHT,
152     SP_ARG_QUERY_ALL,
153     SP_ARG_QUERY_ID,
154     SP_ARG_VERSION,
155     SP_ARG_VACUUM_DEFS,
156     SP_ARG_VERB_LIST,
157     SP_ARG_VERB,
158     SP_ARG_SELECT,
159     SP_ARG_LAST
160 };
162 int sp_main_gui(int argc, char const **argv);
163 int sp_main_console(int argc, char const **argv);
164 static void sp_do_export_png(SPDocument *doc);
165 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
166 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const *mime);
167 #ifdef WIN32
168 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
169 #endif //WIN32
170 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
171 static void do_query_all (SPDocument *doc);
172 static void do_query_all_recurse (SPObject *o);
174 static gchar *sp_global_printer = NULL;
175 static gchar *sp_export_png = NULL;
176 static gchar *sp_export_dpi = NULL;
177 static gchar *sp_export_area = NULL;
178 static gboolean sp_export_area_drawing = FALSE;
179 static gboolean sp_export_area_canvas = FALSE;
180 static gchar *sp_export_width = NULL;
181 static gchar *sp_export_height = NULL;
182 static gchar *sp_export_id = NULL;
183 static gchar *sp_export_background = NULL;
184 static gchar *sp_export_background_opacity = NULL;
185 static gboolean sp_export_area_snap = FALSE;
186 static gboolean sp_export_use_hints = FALSE;
187 static gboolean sp_export_id_only = FALSE;
188 static gchar *sp_export_svg = NULL;
189 static gchar *sp_export_ps = NULL;
190 static gchar *sp_export_eps = NULL;
191 static gchar *sp_export_pdf = NULL;
192 #ifdef WIN32
193 static gchar *sp_export_emf = NULL;
194 #endif //WIN32
195 static gboolean sp_export_text_to_path = FALSE;
196 static gboolean sp_export_font = FALSE;
197 static gboolean sp_export_bbox_page = FALSE;
198 static gboolean sp_query_x = FALSE;
199 static gboolean sp_query_y = FALSE;
200 static gboolean sp_query_width = FALSE;
201 static gboolean sp_query_height = FALSE;
202 static gboolean sp_query_all = FALSE;
203 static gchar *sp_query_id = NULL;
204 static int sp_new_gui = FALSE;
205 static gboolean sp_vacuum_defs = FALSE;
207 static gchar *sp_export_png_utf8 = NULL;
208 static gchar *sp_export_svg_utf8 = NULL;
209 static gchar *sp_global_printer_utf8 = NULL;
211 #ifdef WIN32
212 static bool replaceArgs( int& argc, char**& argv );
213 #endif
214 static GSList *sp_process_args(poptContext ctx);
215 struct poptOption options[] = {
216     {"version", 'V',
217      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
218      N_("Print the Inkscape version number"),
219      NULL},
221     {"without-gui", 'z',
222      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
223      N_("Do not use X server (only process files from console)"),
224      NULL},
226     {"with-gui", 'g',
227      POPT_ARG_NONE, NULL, SP_ARG_GUI,
228      N_("Try to use X server (even if $DISPLAY is not set)"),
229      NULL},
231     {"file", 'f',
232      POPT_ARG_STRING, NULL, SP_ARG_FILE,
233      N_("Open specified document(s) (option string may be excluded)"),
234      N_("FILENAME")},
236     {"print", 'p',
237      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
238      N_("Print document(s) to specified output file (use '| program' for pipe)"),
239      N_("FILENAME")},
241     {"export-png", 'e',
242      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
243      N_("Export document to a PNG file"),
244      N_("FILENAME")},
246     {"export-dpi", 'd',
247      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
248      N_("The resolution used for exporting SVG into bitmap (default 90)"),
249      N_("DPI")},
251     {"export-area", 'a',
252      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
253      N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
254      N_("x0:y0:x1:y1")},
256     {"export-area-drawing", 'D',
257      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
258      N_("Exported area is the entire drawing (not canvas)"),
259      NULL},
261     {"export-area-canvas", 'C',
262      POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
263      N_("Exported area is the entire canvas"),
264      NULL},
266     {"export-area-snap", 0,
267      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
268      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
269      NULL},
271     {"export-width", 'w',
272      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
273      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
274      N_("WIDTH")},
276     {"export-height", 'h',
277      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
278      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
279      N_("HEIGHT")},
281     {"export-id", 'i',
282      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
283      N_("The ID of the object to export"),
284      N_("ID")},
286     {"export-id-only", 'j',
287      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
288      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
289      //  See "man inkscape" for details.
290      N_("Export just the object with export-id, hide all others (only with export-id)"),
291      NULL},
293     {"export-use-hints", 't',
294      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
295      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
296      NULL},
298     {"export-background", 'b',
299      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
300      N_("Background color of exported bitmap (any SVG-supported color string)"),
301      N_("COLOR")},
303     {"export-background-opacity", 'y',
304      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
305      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
306      N_("VALUE")},
308     {"export-plain-svg", 'l',
309      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
310      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
311      N_("FILENAME")},
313     {"export-ps", 'P',
314      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
315      N_("Export document to a PS file"),
316      N_("FILENAME")},
318     {"export-eps", 'E',
319      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
320      N_("Export document to an EPS file"),
321      N_("FILENAME")},
323     {"export-pdf", 'A',
324      POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
325      N_("Export document to a PDF file"),
326      N_("FILENAME")},
328 #ifdef WIN32
329     {"export-emf", 'M',
330      POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
331      N_("Export document to an Enhanced Metafile (EMF) File"),
332      N_("FILENAME")},
333 #endif //WIN32
335     {"export-text-to-path", 'T',
336      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
337      N_("Convert text object to paths on export (EPS)"),
338      NULL},
340     {"export-embed-fonts", 'F',
341      POPT_ARG_NONE, &sp_export_font, SP_ARG_EXPORT_FONT,
342      N_("Embed fonts on export (Type 1 only) (EPS)"),
343      NULL},
345     {"export-bbox-page", 'B',
346      POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
347      N_("Export files with the bounding box set to the page size (EPS)"),
348      NULL},
350     {"query-x", 'X',
351      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
352      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
353      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
354      NULL},
356     {"query-y", 'Y',
357      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
358      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
359      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
360      NULL},
362     {"query-width", 'W',
363      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
364      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
365      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
366      NULL},
368     {"query-height", 'H',
369      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
370      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
371      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
372      NULL},
374     {"query-all", 'S',
375      POPT_ARG_NONE, &sp_query_all, SP_ARG_QUERY_ALL,
376      N_("List id,x,y,w,h for all objects"),
377      NULL},
379     {"query-id", 'I',
380      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
381      N_("The ID of the object whose dimensions are queried"),
382      N_("ID")},
384     {"extension-directory", 'x',
385      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
386      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
387      N_("Print out the extension directory and exit"),
388      NULL},
390     {"vacuum-defs", 0,
391      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
392      N_("Remove unused definitions from the defs section(s) of the document"),
393      NULL},
395     {"verb-list", 0,
396      POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
397      N_("List the IDs of all the verbs in Inkscape"),
398      NULL},
400     {"verb", 0,
401      POPT_ARG_STRING, NULL, SP_ARG_VERB,
402      N_("Verb to call when Inkscape opens."),
403      N_("VERB-ID")},
405     {"select", 0,
406      POPT_ARG_STRING, NULL, SP_ARG_SELECT,
407      N_("Object ID to select when Inkscape opens."),
408      N_("OBJECT-ID")},
410     POPT_AUTOHELP POPT_TABLEEND
411 };
413 static bool needToRecodeParams = true;
414 gchar* blankParam = "";
416 int
417 main(int argc, char **argv)
419 #ifdef HAVE_FPSETMASK
420     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
421        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
422        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
423     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
424 #endif
426 #ifdef ENABLE_NLS
427 #ifdef WIN32
428     RegistryTool rt;
429     rt.setPathInfo();
430     gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
431     bindtextdomain(GETTEXT_PACKAGE, pathBuf);
432     g_free(pathBuf);
433 #else
434 #ifdef ENABLE_BINRELOC
435     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
436 #else
437     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
438 #endif
439 #endif
440     // Allow the user to override the locale directory by setting
441     // the environment variable INKSCAPE_LOCALEDIR.
442     char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
443     if (inkscape_localedir != NULL) {
444         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
445     }
446 #endif
448     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
450 #ifdef ENABLE_NLS
451     textdomain(GETTEXT_PACKAGE);
452 #endif
454     LIBXML_TEST_VERSION
456     Inkscape::GC::init();
458     Inkscape::Debug::Logger::init();
460     gboolean use_gui;
461 #ifndef WIN32
462     use_gui = (getenv("DISPLAY") != NULL);
463 #else
464     /*
465       Set the current directory to the directory of the
466       executable.  This seems redundant, but is needed for
467       when inkscape.exe is executed from another directory.
468       We use relative paths on win32.
469       HKCR\svgfile\shell\open\command is a good example
470     */
471     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
472     char *homedir = g_path_get_dirname(argv[0]);
473     SetCurrentDirectory(homedir);
474     g_free(homedir);
476     use_gui = TRUE;
477 #endif
478     /* Test whether with/without GUI is forced */
479     for (int i = 1; i < argc; i++) {
480         if (!strcmp(argv[i], "-z")
481             || !strcmp(argv[i], "--without-gui")
482             || !strcmp(argv[i], "-p")
483             || !strncmp(argv[i], "--print", 7)
484             || !strcmp(argv[i], "-e")
485             || !strncmp(argv[i], "--export-png", 12)
486             || !strcmp(argv[i], "-l")
487             || !strncmp(argv[i], "--export-plain-svg", 12)
488             || !strcmp(argv[i], "-i")
489             || !strncmp(argv[i], "--export-area-drawing", 21)
490             || !strcmp(argv[i], "-D")
491             || !strncmp(argv[i], "--export-area-canvas", 20)
492             || !strcmp(argv[i], "-C")
493             || !strncmp(argv[i], "--export-id", 12)
494             || !strcmp(argv[i], "-P")
495             || !strncmp(argv[i], "--export-ps", 11)
496             || !strcmp(argv[i], "-E")
497             || !strncmp(argv[i], "--export-eps", 12)
498             || !strcmp(argv[i], "-A")
499             || !strncmp(argv[i], "--export-pdf", 12)
500 #ifdef WIN32
501             || !strcmp(argv[i], "-M")
502             || !strncmp(argv[i], "--export-emf", 12)
503 #endif //WIN32
504             || !strcmp(argv[i], "-W")
505             || !strncmp(argv[i], "--query-width", 13)
506             || !strcmp(argv[i], "-H")
507             || !strncmp(argv[i], "--query-height", 14)
508             || !strcmp(argv[i], "-S")
509             || !strncmp(argv[i], "--query-all", 11)
510             || !strcmp(argv[i], "-X")
511             || !strncmp(argv[i], "--query-x", 13)
512             || !strcmp(argv[i], "-Y")
513             || !strncmp(argv[i], "--query-y", 14)
514             || !strcmp(argv[i], "--vacuum-defs")
515            )
516         {
517             /* main_console handles any exports -- not the gui */
518             use_gui = FALSE;
519             break;
520         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
521             use_gui = TRUE;
522             break;
523         }
524     }
526 #ifdef WIN32
527 #ifndef REPLACEARGS_ANSI
528     if ( PrintWin32::is_os_wide() )
529 #endif // REPLACEARGS_ANSI
530     {
531         // If the call fails, we'll need to convert charsets
532         needToRecodeParams = !replaceArgs( argc, argv );
533     }
534 #endif // WIN32
536     /// \todo  Should this be a static object (see inkscape.cpp)?
537     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
539     return app.run();
542 void fixupSingleFilename( gchar **orig, gchar **spare )
544     if ( orig && *orig && **orig ) {
545         GError *error = NULL;
546         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
547         if ( newFileName )
548         {
549             *orig = newFileName;
550             if ( spare ) {
551                 *spare = newFileName;
552             }
553 //             g_message("Set a replacement fixup");
554         }
555     }
558 GSList *fixupFilenameEncoding( GSList* fl )
560     GSList *newFl = NULL;
561     while ( fl ) {
562         gchar *fn = static_cast<gchar*>(fl->data);
563         fl = g_slist_remove( fl, fl->data );
564         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
565         if ( newFileName ) {
567             if ( 0 )
568             {
569                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
570                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
571                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
572                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
573                 gtk_dialog_run (GTK_DIALOG (w));
574                 gtk_widget_destroy (w);
575                 g_free(safeNewFn);
576                 g_free(safeFn);
577             }
579             g_free( fn );
580             fn = newFileName;
581             newFileName = 0;
582         }
583         else
584             if ( 0 )
585         {
586             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
587             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
588             gtk_dialog_run (GTK_DIALOG (w));
589             gtk_widget_destroy (w);
590             g_free(safeFn);
591         }
592         newFl = g_slist_append( newFl, fn );
593     }
594     return newFl;
597 int sp_common_main( int argc, char const **argv, GSList **flDest )
599     /// \todo fixme: Move these to some centralized location (Lauris)
600     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
601     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
604     // temporarily switch gettext encoding to locale, so that help messages can be output properly
605     gchar const *charset;
606     g_get_charset(&charset);
608     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
610     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
611     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
612     g_return_val_if_fail(ctx != NULL, 1);
614     /* Collect own arguments */
615     GSList *fl = sp_process_args(ctx);
616     poptFreeContext(ctx);
618     // now switch gettext back to UTF-8 (for GUI)
619     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
621     // Now let's see if the file list still holds up
622     if ( needToRecodeParams )
623     {
624         fl = fixupFilenameEncoding( fl );
625     }
627     // Check the globals for filename-fixup
628     if ( needToRecodeParams )
629     {
630         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
631         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
632         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
633     }
634     else
635     {
636         if ( sp_export_png )
637             sp_export_png_utf8 = g_strdup( sp_export_png );
638         if ( sp_export_svg )
639             sp_export_svg_utf8 = g_strdup( sp_export_svg );
640         if ( sp_global_printer )
641             sp_global_printer_utf8 = g_strdup( sp_global_printer );
642     }
644     // Return the list if wanted, else free it up.
645     if ( flDest ) {
646         *flDest = fl;
647         fl = 0;
648     } else {
649         while ( fl ) {
650             g_free( fl->data );
651             fl = g_slist_remove( fl, fl->data );
652         }
653     }
654     return 0;
657 static void
658 snooper(GdkEvent *event, gpointer /*data*/) {
659     if(inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
660     {
661         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
662         switch (event->type) {
663             case GDK_MOTION_NOTIFY:
664                 if(event->motion.state & mapping) {
665                     event->motion.state|=GDK_MOD1_MASK;
666                 }
667                 break;
668             case GDK_BUTTON_PRESS:
669                 if(event->button.state & mapping) {
670                     event->button.state|=GDK_MOD1_MASK;
671                 }
672                 break;
673              case GDK_KEY_PRESS:
674                  if(event->key.state & mapping) {
675                      event->key.state|=GDK_MOD1_MASK;
676                  }
677                  break;
678         default:
679             break;
680         }
681     }
682     gtk_main_do_event (event);
685 int
686 sp_main_gui(int argc, char const **argv)
688     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
690     GSList *fl = NULL;
691     int retVal = sp_common_main( argc, argv, &fl );
692     g_return_val_if_fail(retVal == 0, 1);
694     inkscape_gtk_stock_init();
696     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
698     Inkscape::Debug::log_display_config();
700     /* Set default icon */
701     gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
702     if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
703         gtk_window_set_default_icon_from_file(filename, NULL);
704     }
705     g_free (filename);
706     filename = 0;
708     gboolean create_new = TRUE;
710     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
711     inkscape_application_init(argv[0], true);
713     while (fl) {
714         if (sp_file_open((gchar *)fl->data,NULL)) {
715             create_new=FALSE;
716         }
717         fl = g_slist_remove(fl, fl->data);
718     }
719     if (create_new) {
720         sp_file_new_default();
721     }
723     Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
724     main_instance.run();
726 #ifdef WIN32
727     //We might not need anything here
728     //sp_win32_finish(); <-- this is a NOP func
729 #endif
731     return 0;
734 int
735 sp_main_console(int argc, char const **argv)
737     /* We are started in text mode */
739     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
740      * in a non-Gtk environment.  Used in libnrtype's
741      * FontInstance.cpp and FontFactory.cpp.
742      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
743      */
744     g_type_init();
745     char **argv2 = const_cast<char **>(argv);
746     gtk_init_check( &argc, &argv2 );
747     //setlocale(LC_ALL, "");
749     GSList *fl = NULL;
750     int retVal = sp_common_main( argc, argv, &fl );
751     g_return_val_if_fail(retVal == 0, 1);
753     if (fl == NULL) {
754         g_print("Nothing to do!\n");
755         exit(0);
756     }
758     inkscape_application_init(argv[0], false);
760     while (fl) {
761         SPDocument *doc;
763         doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
764         if (doc == NULL) {
765             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
766         }
767         if (doc == NULL) {
768             g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
769         } else {
770             if (sp_vacuum_defs) {
771                 vacuum_document(doc);
772             }
773             if (sp_vacuum_defs && !sp_export_svg) {
774                 // save under the name given in the command line
775                 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
776             }
777             if (sp_global_printer) {
778                 sp_print_document_to_file(doc, sp_global_printer);
779             }
780             if (sp_export_png || sp_export_id || sp_export_area_drawing) {
781                 sp_do_export_png(doc);
782             }
783             if (sp_export_svg) {
784                 Inkscape::XML::Document *rdoc;
785                 Inkscape::XML::Node *repr;
786                 rdoc = sp_repr_document_new("svg:svg");
787                 repr = rdoc->root();
788                 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
789                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
790             }
791             if (sp_export_ps) {
792                 do_export_ps(doc, sp_export_ps, "image/x-postscript");
793             }
794             if (sp_export_eps) {
795                 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
796             }
797             if (sp_export_pdf) {
798                 do_export_pdf(doc, sp_export_pdf, "application/pdf");
799             }
800 #ifdef WIN32
801             if (sp_export_emf) {
802                 do_export_emf(doc, sp_export_emf, "image/x-emf");
803             }
804 #endif //WIN32
805             if (sp_query_all) {
806                 do_query_all (doc);
807             } else if (sp_query_width || sp_query_height) {
808                 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
809             } else if (sp_query_x || sp_query_y) {
810                 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
811             }
812         }
814         fl = g_slist_remove(fl, fl->data);
815     }
817     inkscape_unref();
819     return 0;
822 static void
823 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
825     SPObject *o = NULL;
827     if (id) {
828         o = doc->getObjectById(id);
829         if (o) {
830             if (!SP_IS_ITEM (o)) {
831                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
832                 return;
833             }
834         } else {
835             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
836             return;
837         }
838     } else {
839         o = SP_DOCUMENT_ROOT(doc);
840     }
842     if (o) {
843         sp_document_ensure_up_to_date (doc);
844         SPItem *item = ((SPItem *) o);
846         // "true" SVG bbox for scripting
847         NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
848         if (area) {
849             Inkscape::SVGOStringStream os;
850             if (extent) {
851                 os << area->extent(axis);
852             } else {
853                 os << area->min()[axis];
854             }
855             g_print ("%s", os.str().c_str());
856         } else {
857             g_print("0");
858         }
859     }
862 static void
863 do_query_all (SPDocument *doc)
865     SPObject *o = NULL;
867     o = SP_DOCUMENT_ROOT(doc);
869     if (o) {
870         sp_document_ensure_up_to_date (doc);
871         do_query_all_recurse(o);
872     }
875 static void
876 do_query_all_recurse (SPObject *o)
878     SPItem *item = ((SPItem *) o);
879     if (o->id && SP_IS_ITEM(item)) {
880         NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
881         if (area) {
882             Inkscape::SVGOStringStream os;
883             os << o->id;
884             os << "," << area->min()[NR::X];
885             os << "," << area->min()[NR::Y];
886             os << "," << area->extent(NR::X);
887             os << "," << area->extent(NR::Y);
888             g_print ("%s\n", os.str().c_str());
889         }
890     }
892     SPObject *child = o->children;
893     while (child) {
894         do_query_all_recurse (child);
895         child = child->next;
896     }
900 static void
901 sp_do_export_png(SPDocument *doc)
903     const gchar *filename = NULL;
904     gdouble dpi = 0.0;
906     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
907         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
908     }
910     GSList *items = NULL;
912     NRRect area;
913     if (sp_export_id || sp_export_area_drawing) {
915         SPObject *o = NULL;
916         SPObject *o_area = NULL;
917         if (sp_export_id && sp_export_area_drawing) {
918             o = doc->getObjectById(sp_export_id);
919             o_area = SP_DOCUMENT_ROOT (doc);
920         } else if (sp_export_id) {
921             o = doc->getObjectById(sp_export_id);
922             o_area = o;
923         } else if (sp_export_area_drawing) {
924             o = SP_DOCUMENT_ROOT (doc);
925             o_area = o;
926         }
928         if (o) {
929             if (!SP_IS_ITEM (o)) {
930                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
931                 return;
932             }
934             items = g_slist_prepend (items, SP_ITEM(o));
936             if (sp_export_id_only) {
937                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
938             }
940             if (sp_export_use_hints) {
942                 // retrieve export filename hint
943                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
944                 if (fn_hint) {
945                     if (sp_export_png) {
946                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
947                         filename = sp_export_png;
948                     } else {
949                         filename = fn_hint;
950                     }
951                 } else {
952                     g_warning ("Export filename hint not found for the object.");
953                     filename = sp_export_png;
954                 }
956                 // retrieve export dpi hints
957                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
958                 if (dpi_hint) {
959                     if (sp_export_dpi || sp_export_width || sp_export_height) {
960                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
961                     } else {
962                         dpi = atof(dpi_hint);
963                     }
964                 } else {
965                     g_warning ("Export DPI hint not found for the object.");
966                 }
968             }
970             // write object bbox to area
971             sp_document_ensure_up_to_date (doc);
972             sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
973         } else {
974             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
975             return;
976         }
977     }
979     if (sp_export_area) {
980         /* Try to parse area (given in SVG pixels) */
981         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
982             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
983             return;
984         }
985         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
986             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
987             return;
988         }
989     } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
990         /* Export the whole canvas */
991         sp_document_ensure_up_to_date (doc);
992         area.x0 = SP_ROOT(doc->root)->x.computed;
993         area.y0 = SP_ROOT(doc->root)->y.computed;
994         area.x1 = area.x0 + sp_document_width (doc);
995         area.y1 = area.y0 + sp_document_height (doc);
996     }
998     // set filename and dpi from options, if not yet set from the hints
999     if (!filename) {
1000         if (!sp_export_png) {
1001             g_warning ("No export filename given and no filename hint. Nothing exported.");
1002             return;
1003         }
1004         filename = sp_export_png;
1005     }
1007     if (sp_export_dpi && dpi == 0.0) {
1008         dpi = atof(sp_export_dpi);
1009         if ((dpi < 0.1) || (dpi > 10000.0)) {
1010             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1011             return;
1012         }
1013         g_print("DPI: %g\n", dpi);
1014     }
1016     if (sp_export_area_snap) {
1017         area.x0 = std::floor (area.x0);
1018         area.y0 = std::floor (area.y0);
1019         area.x1 = std::ceil (area.x1);
1020         area.y1 = std::ceil (area.y1);
1021     }
1023     // default dpi
1024     if (dpi == 0.0)
1025         dpi = PX_PER_IN;
1027     unsigned long int width = 0;
1028     unsigned long int height = 0;
1030     if (sp_export_width) {
1031         width = strtoul(sp_export_width, NULL, 0);
1032         if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1033             g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1034             return;
1035         }
1036         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1037     }
1039     if (sp_export_height) {
1040         height = strtoul(sp_export_height, NULL, 0);
1041         if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1042             g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1043             return;
1044         }
1045         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1046     }
1048     if (!sp_export_width) {
1049         width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1050     }
1052     if (!sp_export_height) {
1053         height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1054     }
1056     guint32 bgcolor = 0x00000000;
1057     if (sp_export_background) {
1058         // override the page color
1059         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1060         bgcolor |= 0xff; // default is no opacity
1061     } else {
1062         // read from namedview
1063         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1064         if (nv && nv->attribute("pagecolor"))
1065             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1066         if (nv && nv->attribute("inkscape:pageopacity"))
1067             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1068     }
1070     if (sp_export_background_opacity) {
1071         // override opacity
1072         gfloat value;
1073         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1074             if (value > 1.0) {
1075                 value = CLAMP (value, 1.0f, 255.0f);
1076                 bgcolor &= (guint32) 0xffffff00;
1077                 bgcolor |= (guint32) floor(value);
1078             } else {
1079                 value = CLAMP (value, 0.0f, 1.0f);
1080                 bgcolor &= (guint32) 0xffffff00;
1081                 bgcolor |= SP_COLOR_F_TO_U(value);
1082             }
1083         }
1084     }
1086     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1088     g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area.x0, area.y0, area.x1, area.y1, width, height, dpi);
1090     g_print("Bitmap saved as: %s\n", filename);
1092     if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1093         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);
1094     } else {
1095         g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1096     }
1098     g_slist_free (items);
1102 /**
1103  *  Perform an export of either PS or EPS.
1104  *
1105  *  \param doc Document to export.
1106  *  \param uri URI to export to.
1107  *  \param mime MIME type to export as.
1108  */
1110 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1112     Inkscape::Extension::DB::OutputList o;
1113     Inkscape::Extension::db.get_output_list(o);
1114     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1115     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1116         i++;
1117     }
1119     if (i == o.end())
1120     {
1121         g_warning ("Could not find an extension to export this file.");
1122         return;
1123     }
1125     bool old_text_to_path = false;
1126     bool old_font_embedded = false;
1127     bool old_bbox_page = false;
1129     try {
1130         old_text_to_path = (*i)->get_param_bool("textToPath");
1131         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1132     }
1133     catch (...) {
1134         g_warning ("Could not set export-text-to-path option for this export.");
1135     }
1137     try {
1138         old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1139         (*i)->set_param_bool("fontEmbedded", sp_export_font);
1140     }
1141     catch (...) {
1142         g_warning ("Could not set export-font option for this export.");
1143     }
1145     try {
1146         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1147         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1148     }
1149     catch (...) {
1150         g_warning ("Could not set export-bbox-page option for this export.");
1151     }
1153     (*i)->save(doc, uri);
1155     try {
1156         (*i)->set_param_bool("textToPath", old_text_to_path);
1157         (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1158         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1159     }
1160     catch (...) {
1162     }
1165 /**
1166  *  Perform a PDF export
1167  *
1168  *  \param doc Document to export.
1169  *  \param uri URI to export to.
1170  *  \param mime MIME type to export as.
1171  */
1173 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1175     Inkscape::Extension::DB::OutputList o;
1176     Inkscape::Extension::db.get_output_list(o);
1177     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1178     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1179         i++;
1180     }
1182     if (i == o.end())
1183     {
1184         g_warning ("Could not find an extension to export this file.");
1185         return;
1186     }
1188     (*i)->save(doc, uri);
1191 #ifdef WIN32
1192 /**
1193  *  Export a document to EMF
1194  *
1195  *  \param doc Document to export.
1196  *  \param uri URI to export to.
1197  *  \param mime MIME type to export as (should be "image/x-emf")
1198  */
1200 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1202     Inkscape::Extension::DB::OutputList o;
1203     Inkscape::Extension::db.get_output_list(o);
1204     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1205     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1206         i++;
1207     }
1209     if (i == o.end())
1210     {
1211         g_warning ("Could not find an extension to export this file.");
1212         return;
1213     }
1215     (*i)->save(doc, uri);
1217 #endif //WIN32
1219 #ifdef WIN32
1220 bool replaceArgs( int& argc, char**& argv )
1222     bool worked = false;
1224 #ifdef REPLACEARGS_DEBUG
1225     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1226 #endif // REPLACEARGS_DEBUG
1228     wchar_t* line = GetCommandLineW();
1229     if ( line )
1230     {
1231 #ifdef REPLACEARGS_DEBUG
1232         {
1233             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1234             if ( utf8Line )
1235             {
1236                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1237                 {
1238                     char tmp[strlen(safe) + 32];
1239                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1240                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1241                 }
1242             }
1243         }
1244 #endif // REPLACEARGS_DEBUG
1246         int numArgs = 0;
1247         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1249 #ifdef REPLACEARGS_ANSI
1250 // test code for trying things on Win95/98/ME
1251         if ( !parsed )
1252         {
1253 #ifdef REPLACEARGS_DEBUG
1254             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1255 #endif // REPLACEARGS_DEBUG
1256             int lineLen = wcslen(line) + 1;
1257             wchar_t* lineDup = new wchar_t[lineLen];
1258             wcsncpy( lineDup, line, lineLen );
1260             int pos = 0;
1261             bool inQuotes = false;
1262             bool inWhitespace = true;
1263             std::vector<int> places;
1264             while ( lineDup[pos] )
1265             {
1266                 if ( inQuotes )
1267                 {
1268                     if ( lineDup[pos] == L'"' )
1269                     {
1270                         inQuotes = false;
1271                     }
1272                 }
1273                 else if ( lineDup[pos] == L'"' )
1274                 {
1275                     inQuotes = true;
1276                     inWhitespace = false;
1277                     places.push_back(pos);
1278                 }
1279                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1280                 {
1281                     if ( !inWhitespace )
1282                     {
1283                         inWhitespace = true;
1284                         lineDup[pos] = 0;
1285                     }
1286                 }
1287                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1288                 {
1289                     inWhitespace = false;
1290                     places.push_back(pos);
1291                 }
1292                 else
1293                 {
1294                     // consume
1295                 }
1296                 pos++;
1297             }
1298 #ifdef REPLACEARGS_DEBUG
1299             {
1300                 char tmp[256];
1301                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1302                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1303             }
1304 #endif // REPLACEARGS_DEBUG
1306             wchar_t** block = new wchar_t*[places.size()];
1307             int i = 0;
1308             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1309             {
1310                 block[i++] = &lineDup[*it];
1311             }
1312             parsed = block;
1313             numArgs = places.size();
1314         }
1315 #endif // REPLACEARGS_ANSI
1317         if ( parsed )
1318         {
1319             std::vector<wchar_t*>expandedArgs;
1320             if ( numArgs > 0 )
1321             {
1322                 expandedArgs.push_back( parsed[0] );
1323             }
1325             for ( int i1 = 1; i1 < numArgs; i1++ )
1326             {
1327                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1328                 wildcarded &= parsed[i1][0] != L'"';
1329                 wildcarded &= parsed[i1][0] != L'-';
1330                 if ( wildcarded )
1331                 {
1332 #ifdef REPLACEARGS_ANSI
1333                     WIN32_FIND_DATAA data = {0};
1334 #else
1335                     WIN32_FIND_DATAW data = {0};
1336 #endif // REPLACEARGS_ANSI
1338                     int baseLen = wcslen(parsed[i1]) + 2;
1339                     wchar_t* base = new wchar_t[baseLen];
1340                     wcsncpy( base, parsed[i1], baseLen );
1341                     wchar_t* last = wcsrchr( base, L'\\' );
1342                     if ( last )
1343                     {
1344                         last[1] = 0;
1345                     }
1346                     else
1347                     {
1348                         base[0] = 0;
1349                     }
1350                     baseLen = wcslen( base );
1352 #ifdef REPLACEARGS_ANSI
1353                     char target[MAX_PATH];
1354                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1355                     {
1356                         HANDLE hf = FindFirstFileA( target, &data );
1357 #else
1358                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1359 #endif // REPLACEARGS_ANSI
1360                         if ( hf != INVALID_HANDLE_VALUE )
1361                         {
1362                             BOOL found = TRUE;
1363                             do
1364                             {
1365 #ifdef REPLACEARGS_ANSI
1366                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1367                                 if ( howMany > 0 )
1368                                 {
1369                                     howMany += baseLen;
1370                                     wchar_t* tmp = new wchar_t[howMany + 1];
1371                                     wcsncpy( tmp, base, howMany + 1 );
1372                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1373                                     expandedArgs.push_back( tmp );
1374                                     found = FindNextFileA( hf, &data );
1375                                 }
1376 #else
1377                                 int howMany = wcslen(data.cFileName) + baseLen;
1378                                 wchar_t* tmp = new wchar_t[howMany + 1];
1379                                 wcsncpy( tmp, base, howMany + 1 );
1380                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1381                                 expandedArgs.push_back( tmp );
1382                                 found = FindNextFileW( hf, &data );
1383 #endif // REPLACEARGS_ANSI
1384                             } while ( found );
1386                             FindClose( hf );
1387                         }
1388                         else
1389                         {
1390                             expandedArgs.push_back( parsed[i1] );
1391                         }
1392 #ifdef REPLACEARGS_ANSI
1393                     }
1394 #endif // REPLACEARGS_ANSI
1396                     delete[] base;
1397                 }
1398                 else
1399                 {
1400                     expandedArgs.push_back( parsed[i1] );
1401                 }
1402             }
1404             {
1405                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1406                 int iz = 0;
1407                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1408                 {
1409                     block[iz++] = *it;
1410                 }
1411                 parsed = block;
1412                 numArgs = expandedArgs.size();
1413             }
1415             std::vector<gchar*> newArgs;
1416             for ( int i = 0; i < numArgs; i++ )
1417             {
1418                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1419                 if ( replacement )
1420                 {
1421 #ifdef REPLACEARGS_DEBUG
1422                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1424                     if ( safe2 )
1425                     {
1426                         {
1427                             char tmp[1024];
1428                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1429                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1430                         }
1431                         g_free( safe2 );
1432                     }
1433 #endif // REPLACEARGS_DEBUG
1435                     newArgs.push_back( replacement );
1436                 }
1437                 else
1438                 {
1439                     newArgs.push_back( blankParam );
1440                 }
1441             }
1443             // Now push our munged params to be the new argv and argc
1444             {
1445                 char** block = new char*[newArgs.size()];
1446                 int iz = 0;
1447                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1448                 {
1449                     block[iz++] = *it;
1450                 }
1451                 argv = block;
1452                 argc = newArgs.size();
1453                 worked = true;
1454             }
1455         }
1456 #ifdef REPLACEARGS_DEBUG
1457         else
1458         {
1459             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1460         }
1461 #endif // REPLACEARGS_DEBUG
1462     }
1463 #ifdef REPLACEARGS_DEBUG
1464     else
1465     {
1466         {
1467             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1468         }
1470         char* line2 = GetCommandLineA();
1471         if ( line2 )
1472         {
1473             gchar *safe = Inkscape::IO::sanitizeString(line2);
1474             {
1475                 {
1476                     char tmp[strlen(safe) + 32];
1477                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1478                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1479                 }
1480             }
1481         }
1482         else
1483         {
1484             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1485         }
1486     }
1487 #endif // REPLACEARGS_DEBUG
1489     return worked;
1491 #endif // WIN32
1493 static GSList *
1494 sp_process_args(poptContext ctx)
1496     GSList *fl = NULL;
1498     gint a;
1499     while ((a = poptGetNextOpt(ctx)) >= 0) {
1500         switch (a) {
1501             case SP_ARG_FILE: {
1502                 gchar const *fn = poptGetOptArg(ctx);
1503                 if (fn != NULL) {
1504                     fl = g_slist_append(fl, g_strdup(fn));
1505                 }
1506                 break;
1507             }
1508             case SP_ARG_VERSION: {
1509                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1510                 exit(0);
1511                 break;
1512             }
1513             case SP_ARG_EXTENSIONDIR: {
1514                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1515                 exit(0);
1516                 break;
1517             }
1518             case SP_ARG_VERB_LIST: {
1519                 // This really shouldn't go here, we should init the app.
1520                 // But, since we're just exiting in this path, there is
1521                 // no harm, and this is really a better place to put
1522                 // everything else.
1523                 Inkscape::Extension::init();
1524                 Inkscape::Verb::list();
1525                 exit(0);
1526                 break;
1527             }
1528             case SP_ARG_VERB:
1529             case SP_ARG_SELECT: {
1530                 gchar const *arg = poptGetOptArg(ctx);
1531                 if (arg != NULL) {
1532                     // printf("Adding in: %s\n", arg);
1533                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1534                 }
1535                 break;
1536             }
1537             default: {
1538                 break;
1539             }
1540         }
1541     }
1543     gchar const ** const args = poptGetArgs(ctx);
1544     if (args != NULL) {
1545         for (unsigned i = 0; args[i] != NULL; i++) {
1546             fl = g_slist_append(fl, g_strdup(args[i]));
1547         }
1548     }
1550     return fl;
1554 /*
1555   Local Variables:
1556   mode:c++
1557   c-file-style:"stroustrup"
1558   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1559   indent-tabs-mode:nil
1560   fill-column:99
1561   End:
1562 */
1563 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :