Code

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