Code

df62e8d0dbdf62d274d228d4d8ec40951e91dd8c
[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) {
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 to MIME type %s.", mime);
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 to MIME type %s.", mime);
1185         return;
1186     }
1188     if (sp_export_id) {
1189         SPObject *o = doc->getObjectById(sp_export_id);
1190         if (o == NULL) {
1191             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1192             return;
1193         }
1194         (*i)->set_param_string ("exportId", sp_export_id);
1195     } else {
1196         (*i)->set_param_string ("exportId", "");
1197     }
1199     if (sp_export_area_drawing) {
1200         (*i)->set_param_bool ("exportDrawing", TRUE);
1201     } else {
1202         (*i)->set_param_bool ("exportDrawing", FALSE);
1203     }
1205     (*i)->save(doc, uri);
1208 #ifdef WIN32
1209 /**
1210  *  Export a document to EMF
1211  *
1212  *  \param doc Document to export.
1213  *  \param uri URI to export to.
1214  *  \param mime MIME type to export as (should be "image/x-emf")
1215  */
1217 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1219     Inkscape::Extension::DB::OutputList o;
1220     Inkscape::Extension::db.get_output_list(o);
1221     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1222     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1223         i++;
1224     }
1226     if (i == o.end())
1227     {
1228         g_warning ("Could not find an extension to export to MIME type %s.", mime);
1229         return;
1230     }
1232     (*i)->save(doc, uri);
1234 #endif //WIN32
1236 #ifdef WIN32
1237 bool replaceArgs( int& argc, char**& argv )
1239     bool worked = false;
1241 #ifdef REPLACEARGS_DEBUG
1242     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1243 #endif // REPLACEARGS_DEBUG
1245     wchar_t* line = GetCommandLineW();
1246     if ( line )
1247     {
1248 #ifdef REPLACEARGS_DEBUG
1249         {
1250             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1251             if ( utf8Line )
1252             {
1253                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1254                 {
1255                     char tmp[strlen(safe) + 32];
1256                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1257                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1258                 }
1259             }
1260         }
1261 #endif // REPLACEARGS_DEBUG
1263         int numArgs = 0;
1264         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1266 #ifdef REPLACEARGS_ANSI
1267 // test code for trying things on Win95/98/ME
1268         if ( !parsed )
1269         {
1270 #ifdef REPLACEARGS_DEBUG
1271             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1272 #endif // REPLACEARGS_DEBUG
1273             int lineLen = wcslen(line) + 1;
1274             wchar_t* lineDup = new wchar_t[lineLen];
1275             wcsncpy( lineDup, line, lineLen );
1277             int pos = 0;
1278             bool inQuotes = false;
1279             bool inWhitespace = true;
1280             std::vector<int> places;
1281             while ( lineDup[pos] )
1282             {
1283                 if ( inQuotes )
1284                 {
1285                     if ( lineDup[pos] == L'"' )
1286                     {
1287                         inQuotes = false;
1288                     }
1289                 }
1290                 else if ( lineDup[pos] == L'"' )
1291                 {
1292                     inQuotes = true;
1293                     inWhitespace = false;
1294                     places.push_back(pos);
1295                 }
1296                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1297                 {
1298                     if ( !inWhitespace )
1299                     {
1300                         inWhitespace = true;
1301                         lineDup[pos] = 0;
1302                     }
1303                 }
1304                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1305                 {
1306                     inWhitespace = false;
1307                     places.push_back(pos);
1308                 }
1309                 else
1310                 {
1311                     // consume
1312                 }
1313                 pos++;
1314             }
1315 #ifdef REPLACEARGS_DEBUG
1316             {
1317                 char tmp[256];
1318                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1319                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1320             }
1321 #endif // REPLACEARGS_DEBUG
1323             wchar_t** block = new wchar_t*[places.size()];
1324             int i = 0;
1325             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1326             {
1327                 block[i++] = &lineDup[*it];
1328             }
1329             parsed = block;
1330             numArgs = places.size();
1331         }
1332 #endif // REPLACEARGS_ANSI
1334         if ( parsed )
1335         {
1336             std::vector<wchar_t*>expandedArgs;
1337             if ( numArgs > 0 )
1338             {
1339                 expandedArgs.push_back( parsed[0] );
1340             }
1342             for ( int i1 = 1; i1 < numArgs; i1++ )
1343             {
1344                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1345                 wildcarded &= parsed[i1][0] != L'"';
1346                 wildcarded &= parsed[i1][0] != L'-';
1347                 if ( wildcarded )
1348                 {
1349 #ifdef REPLACEARGS_ANSI
1350                     WIN32_FIND_DATAA data = {0};
1351 #else
1352                     WIN32_FIND_DATAW data = {0};
1353 #endif // REPLACEARGS_ANSI
1355                     int baseLen = wcslen(parsed[i1]) + 2;
1356                     wchar_t* base = new wchar_t[baseLen];
1357                     wcsncpy( base, parsed[i1], baseLen );
1358                     wchar_t* last = wcsrchr( base, L'\\' );
1359                     if ( last )
1360                     {
1361                         last[1] = 0;
1362                     }
1363                     else
1364                     {
1365                         base[0] = 0;
1366                     }
1367                     baseLen = wcslen( base );
1369 #ifdef REPLACEARGS_ANSI
1370                     char target[MAX_PATH];
1371                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1372                     {
1373                         HANDLE hf = FindFirstFileA( target, &data );
1374 #else
1375                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1376 #endif // REPLACEARGS_ANSI
1377                         if ( hf != INVALID_HANDLE_VALUE )
1378                         {
1379                             BOOL found = TRUE;
1380                             do
1381                             {
1382 #ifdef REPLACEARGS_ANSI
1383                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1384                                 if ( howMany > 0 )
1385                                 {
1386                                     howMany += baseLen;
1387                                     wchar_t* tmp = new wchar_t[howMany + 1];
1388                                     wcsncpy( tmp, base, howMany + 1 );
1389                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1390                                     expandedArgs.push_back( tmp );
1391                                     found = FindNextFileA( hf, &data );
1392                                 }
1393 #else
1394                                 int howMany = wcslen(data.cFileName) + baseLen;
1395                                 wchar_t* tmp = new wchar_t[howMany + 1];
1396                                 wcsncpy( tmp, base, howMany + 1 );
1397                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1398                                 expandedArgs.push_back( tmp );
1399                                 found = FindNextFileW( hf, &data );
1400 #endif // REPLACEARGS_ANSI
1401                             } while ( found );
1403                             FindClose( hf );
1404                         }
1405                         else
1406                         {
1407                             expandedArgs.push_back( parsed[i1] );
1408                         }
1409 #ifdef REPLACEARGS_ANSI
1410                     }
1411 #endif // REPLACEARGS_ANSI
1413                     delete[] base;
1414                 }
1415                 else
1416                 {
1417                     expandedArgs.push_back( parsed[i1] );
1418                 }
1419             }
1421             {
1422                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1423                 int iz = 0;
1424                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1425                 {
1426                     block[iz++] = *it;
1427                 }
1428                 parsed = block;
1429                 numArgs = expandedArgs.size();
1430             }
1432             std::vector<gchar*> newArgs;
1433             for ( int i = 0; i < numArgs; i++ )
1434             {
1435                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1436                 if ( replacement )
1437                 {
1438 #ifdef REPLACEARGS_DEBUG
1439                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1441                     if ( safe2 )
1442                     {
1443                         {
1444                             char tmp[1024];
1445                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1446                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1447                         }
1448                         g_free( safe2 );
1449                     }
1450 #endif // REPLACEARGS_DEBUG
1452                     newArgs.push_back( replacement );
1453                 }
1454                 else
1455                 {
1456                     newArgs.push_back( blankParam );
1457                 }
1458             }
1460             // Now push our munged params to be the new argv and argc
1461             {
1462                 char** block = new char*[newArgs.size()];
1463                 int iz = 0;
1464                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1465                 {
1466                     block[iz++] = *it;
1467                 }
1468                 argv = block;
1469                 argc = newArgs.size();
1470                 worked = true;
1471             }
1472         }
1473 #ifdef REPLACEARGS_DEBUG
1474         else
1475         {
1476             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1477         }
1478 #endif // REPLACEARGS_DEBUG
1479     }
1480 #ifdef REPLACEARGS_DEBUG
1481     else
1482     {
1483         {
1484             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1485         }
1487         char* line2 = GetCommandLineA();
1488         if ( line2 )
1489         {
1490             gchar *safe = Inkscape::IO::sanitizeString(line2);
1491             {
1492                 {
1493                     char tmp[strlen(safe) + 32];
1494                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1495                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1496                 }
1497             }
1498         }
1499         else
1500         {
1501             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1502         }
1503     }
1504 #endif // REPLACEARGS_DEBUG
1506     return worked;
1508 #endif // WIN32
1510 static GSList *
1511 sp_process_args(poptContext ctx)
1513     GSList *fl = NULL;
1515     gint a;
1516     while ((a = poptGetNextOpt(ctx)) >= 0) {
1517         switch (a) {
1518             case SP_ARG_FILE: {
1519                 gchar const *fn = poptGetOptArg(ctx);
1520                 if (fn != NULL) {
1521                     fl = g_slist_append(fl, g_strdup(fn));
1522                 }
1523                 break;
1524             }
1525             case SP_ARG_VERSION: {
1526                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1527                 exit(0);
1528                 break;
1529             }
1530             case SP_ARG_EXTENSIONDIR: {
1531                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1532                 exit(0);
1533                 break;
1534             }
1535             case SP_ARG_VERB_LIST: {
1536                 // This really shouldn't go here, we should init the app.
1537                 // But, since we're just exiting in this path, there is
1538                 // no harm, and this is really a better place to put
1539                 // everything else.
1540                 Inkscape::Extension::init();
1541                 Inkscape::Verb::list();
1542                 exit(0);
1543                 break;
1544             }
1545             case SP_ARG_VERB:
1546             case SP_ARG_SELECT: {
1547                 gchar const *arg = poptGetOptArg(ctx);
1548                 if (arg != NULL) {
1549                     // printf("Adding in: %s\n", arg);
1550                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1551                 }
1552                 break;
1553             }
1554             default: {
1555                 break;
1556             }
1557         }
1558     }
1560     gchar const ** const args = poptGetArgs(ctx);
1561     if (args != NULL) {
1562         for (unsigned i = 0; args[i] != NULL; i++) {
1563             fl = g_slist_append(fl, g_strdup(args[i]));
1564         }
1565     }
1567     return fl;
1571 /*
1572   Local Variables:
1573   mode:c++
1574   c-file-style:"stroustrup"
1575   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1576   indent-tabs-mode:nil
1577   fill-column:99
1578   End:
1579 */
1580 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :