Code

hopefully fix compile (#include <errno.h>
[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_ID,
152     SP_ARG_VERSION,
153     SP_ARG_VACUUM_DEFS,
154     SP_ARG_VERB_LIST,
155     SP_ARG_VERB,
156     SP_ARG_SELECT,
157     SP_ARG_LAST
158 };
160 int sp_main_gui(int argc, char const **argv);
161 int sp_main_console(int argc, char const **argv);
162 static void sp_do_export_png(SPDocument *doc);
163 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
164 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const *mime);
165 #ifdef WIN32
166 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
167 #endif //WIN32
168 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
171 static gchar *sp_global_printer = NULL;
172 static gchar *sp_export_png = NULL;
173 static gchar *sp_export_dpi = NULL;
174 static gchar *sp_export_area = NULL;
175 static gboolean sp_export_area_drawing = FALSE;
176 static gboolean sp_export_area_canvas = FALSE;
177 static gchar *sp_export_width = NULL;
178 static gchar *sp_export_height = NULL;
179 static gchar *sp_export_id = NULL;
180 static gchar *sp_export_background = NULL;
181 static gchar *sp_export_background_opacity = NULL;
182 static gboolean sp_export_area_snap = FALSE;
183 static gboolean sp_export_use_hints = FALSE;
184 static gboolean sp_export_id_only = FALSE;
185 static gchar *sp_export_svg = NULL;
186 static gchar *sp_export_ps = NULL;
187 static gchar *sp_export_eps = NULL;
188 static gchar *sp_export_pdf = NULL;
189 #ifdef WIN32
190 static gchar *sp_export_emf = NULL;
191 #endif //WIN32
192 static gboolean sp_export_text_to_path = FALSE;
193 static gboolean sp_export_font = FALSE;
194 static gboolean sp_export_bbox_page = FALSE;
195 static gboolean sp_query_x = FALSE;
196 static gboolean sp_query_y = FALSE;
197 static gboolean sp_query_width = FALSE;
198 static gboolean sp_query_height = FALSE;
199 static gchar *sp_query_id = NULL;
200 static int sp_new_gui = FALSE;
201 static gboolean sp_vacuum_defs = FALSE;
203 static gchar *sp_export_png_utf8 = NULL;
204 static gchar *sp_export_svg_utf8 = NULL;
205 static gchar *sp_global_printer_utf8 = NULL;
207 #ifdef WIN32
208 static bool replaceArgs( int& argc, char**& argv );
209 #endif
210 static GSList *sp_process_args(poptContext ctx);
211 struct poptOption options[] = {
212     {"version", 'V',
213      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
214      N_("Print the Inkscape version number"),
215      NULL},
217     {"without-gui", 'z',
218      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
219      N_("Do not use X server (only process files from console)"),
220      NULL},
222     {"with-gui", 'g',
223      POPT_ARG_NONE, NULL, SP_ARG_GUI,
224      N_("Try to use X server (even if $DISPLAY is not set)"),
225      NULL},
227     {"file", 'f',
228      POPT_ARG_STRING, NULL, SP_ARG_FILE,
229      N_("Open specified document(s) (option string may be excluded)"),
230      N_("FILENAME")},
232     {"print", 'p',
233      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
234      N_("Print document(s) to specified output file (use '| program' for pipe)"),
235      N_("FILENAME")},
237     {"export-png", 'e',
238      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
239      N_("Export document to a PNG file"),
240      N_("FILENAME")},
242     {"export-dpi", 'd',
243      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
244      N_("The resolution used for exporting SVG into bitmap (default 90)"),
245      N_("DPI")},
247     {"export-area", 'a',
248      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
249      N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
250      N_("x0:y0:x1:y1")},
252     {"export-area-drawing", 'D',
253      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
254      N_("Exported area is the entire drawing (not canvas)"),
255      NULL},
257     {"export-area-canvas", 'C',
258      POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
259      N_("Exported area is the entire canvas"),
260      NULL},
262     {"export-area-snap", 0,
263      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
264      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
265      NULL},
267     {"export-width", 'w',
268      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
269      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
270      N_("WIDTH")},
272     {"export-height", 'h',
273      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
274      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
275      N_("HEIGHT")},
277     {"export-id", 'i',
278      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
279      N_("The ID of the object to export"),
280      N_("ID")},
282     {"export-id-only", 'j',
283      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
284      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
285      //  See "man inkscape" for details.
286      N_("Export just the object with export-id, hide all others (only with export-id)"),
287      NULL},
289     {"export-use-hints", 't',
290      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
291      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
292      NULL},
294     {"export-background", 'b',
295      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
296      N_("Background color of exported bitmap (any SVG-supported color string)"),
297      N_("COLOR")},
299     {"export-background-opacity", 'y',
300      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
301      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
302      N_("VALUE")},
304     {"export-plain-svg", 'l',
305      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
306      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
307      N_("FILENAME")},
309     {"export-ps", 'P',
310      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
311      N_("Export document to a PS file"),
312      N_("FILENAME")},
314     {"export-eps", 'E',
315      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
316      N_("Export document to an EPS file"),
317      N_("FILENAME")},
319     {"export-pdf", 'A',
320      POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
321      N_("Export document to a PDF file"),
322      N_("FILENAME")},
324 #ifdef WIN32
325     {"export-emf", 'M',
326      POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
327      N_("Export document to an Enhanced Metafile (EMF) File"),
328      N_("FILENAME")},
329 #endif //WIN32
331     {"export-text-to-path", 'T',
332      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
333      N_("Convert text object to paths on export (EPS)"),
334      NULL},
336     {"export-embed-fonts", 'F',
337      POPT_ARG_NONE, &sp_export_font, SP_ARG_EXPORT_FONT,
338      N_("Embed fonts on export (Type 1 only) (EPS)"),
339      NULL},
341     {"export-bbox-page", 'B',
342      POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
343      N_("Export files with the bounding box set to the page size (EPS)"),
344      NULL},
346     {"query-x", 'X',
347      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
348      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
349      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
350      NULL},
352     {"query-y", 'Y',
353      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
354      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
355      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
356      NULL},
358     {"query-width", 'W',
359      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
360      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
361      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
362      NULL},
364     {"query-height", 'H',
365      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
366      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
367      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
368      NULL},
370     {"query-id", 'I',
371      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
372      N_("The ID of the object whose dimensions are queried"),
373      N_("ID")},
375     {"extension-directory", 'x',
376      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
377      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
378      N_("Print out the extension directory and exit"),
379      NULL},
381     {"vacuum-defs", 0,
382      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
383      N_("Remove unused definitions from the defs section(s) of the document"),
384      NULL},
386     {"verb-list", 0,
387      POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
388      N_("List the IDs of all the verbs in Inkscape"),
389      NULL},
391     {"verb", 0,
392      POPT_ARG_STRING, NULL, SP_ARG_VERB,
393      N_("Verb to call when Inkscape opens."),
394      N_("VERB-ID")},
396     {"select", 0,
397      POPT_ARG_STRING, NULL, SP_ARG_SELECT,
398      N_("Object ID to select when Inkscape opens."),
399      N_("OBJECT-ID")},
401     POPT_AUTOHELP POPT_TABLEEND
402 };
404 static bool needToRecodeParams = true;
405 gchar* blankParam = "";
407 int
408 main(int argc, char **argv)
410 #ifdef HAVE_FPSETMASK
411     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
412        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
413        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
414     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
415 #endif
417 #ifdef ENABLE_NLS
418 #ifdef WIN32
419     RegistryTool rt;
420     rt.setPathInfo();
421     gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
422     bindtextdomain(GETTEXT_PACKAGE, pathBuf);
423     g_free(pathBuf);
424 #else
425 #ifdef ENABLE_BINRELOC
426     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
427 #else
428     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
429 #endif
430 #endif
431     // Allow the user to override the locale directory by setting
432     // the environment variable INKSCAPE_LOCALEDIR.
433     char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
434     if (inkscape_localedir != NULL) {
435         bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
436     }
437 #endif
439     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
441 #ifdef ENABLE_NLS
442     textdomain(GETTEXT_PACKAGE);
443 #endif
445     LIBXML_TEST_VERSION
447     Inkscape::GC::init();
449     Inkscape::Debug::Logger::init();
451     gboolean use_gui;
452 #ifndef WIN32
453     use_gui = (getenv("DISPLAY") != NULL);
454 #else
455     /*
456       Set the current directory to the directory of the
457       executable.  This seems redundant, but is needed for
458       when inkscape.exe is executed from another directory.
459       We use relative paths on win32.
460       HKCR\svgfile\shell\open\command is a good example
461     */
462     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
463     char *homedir = g_path_get_dirname(argv[0]);
464     SetCurrentDirectory(homedir);
465     g_free(homedir);
467     use_gui = TRUE;
468 #endif
469     /* Test whether with/without GUI is forced */
470     for (int i = 1; i < argc; i++) {
471         if (!strcmp(argv[i], "-z")
472             || !strcmp(argv[i], "--without-gui")
473             || !strcmp(argv[i], "-p")
474             || !strncmp(argv[i], "--print", 7)
475             || !strcmp(argv[i], "-e")
476             || !strncmp(argv[i], "--export-png", 12)
477             || !strcmp(argv[i], "-l")
478             || !strncmp(argv[i], "--export-plain-svg", 12)
479             || !strcmp(argv[i], "-i")
480             || !strncmp(argv[i], "--export-area-drawing", 21)
481             || !strcmp(argv[i], "-D")
482             || !strncmp(argv[i], "--export-area-canvas", 20)
483             || !strcmp(argv[i], "-C")
484             || !strncmp(argv[i], "--export-id", 12)
485             || !strcmp(argv[i], "-P")
486             || !strncmp(argv[i], "--export-ps", 11)
487             || !strcmp(argv[i], "-E")
488             || !strncmp(argv[i], "--export-eps", 12)
489             || !strcmp(argv[i], "-A")
490             || !strncmp(argv[i], "--export-pdf", 12)
491 #ifdef WIN32
492             || !strcmp(argv[i], "-M")
493             || !strncmp(argv[i], "--export-emf", 12)
494 #endif //WIN32
495             || !strcmp(argv[i], "-W")
496             || !strncmp(argv[i], "--query-width", 13)
497             || !strcmp(argv[i], "-H")
498             || !strncmp(argv[i], "--query-height", 14)
499             || !strcmp(argv[i], "-X")
500             || !strncmp(argv[i], "--query-x", 13)
501             || !strcmp(argv[i], "-Y")
502             || !strncmp(argv[i], "--query-y", 14)
503             || !strcmp(argv[i], "--vacuum-defs")
504            )
505         {
506             /* main_console handles any exports -- not the gui */
507             use_gui = FALSE;
508             break;
509         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
510             use_gui = TRUE;
511             break;
512         }
513     }
515 #ifdef WIN32
516 #ifndef REPLACEARGS_ANSI
517     if ( PrintWin32::is_os_wide() )
518 #endif // REPLACEARGS_ANSI
519     {
520         // If the call fails, we'll need to convert charsets
521         needToRecodeParams = !replaceArgs( argc, argv );
522     }
523 #endif // WIN32
525     /// \todo  Should this be a static object (see inkscape.cpp)?
526     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
528     return app.run();
531 void fixupSingleFilename( gchar **orig, gchar **spare )
533     if ( orig && *orig && **orig ) {
534         GError *error = NULL;
535         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
536         if ( newFileName )
537         {
538             *orig = newFileName;
539             if ( spare ) {
540                 *spare = newFileName;
541             }
542 //             g_message("Set a replacement fixup");
543         }
544     }
547 GSList *fixupFilenameEncoding( GSList* fl )
549     GSList *newFl = NULL;
550     while ( fl ) {
551         gchar *fn = static_cast<gchar*>(fl->data);
552         fl = g_slist_remove( fl, fl->data );
553         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
554         if ( newFileName ) {
556             if ( 0 )
557             {
558                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
559                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
560                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
561                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
562                 gtk_dialog_run (GTK_DIALOG (w));
563                 gtk_widget_destroy (w);
564                 g_free(safeNewFn);
565                 g_free(safeFn);
566             }
568             g_free( fn );
569             fn = newFileName;
570             newFileName = 0;
571         }
572         else
573             if ( 0 )
574         {
575             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
576             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
577             gtk_dialog_run (GTK_DIALOG (w));
578             gtk_widget_destroy (w);
579             g_free(safeFn);
580         }
581         newFl = g_slist_append( newFl, fn );
582     }
583     return newFl;
586 int sp_common_main( int argc, char const **argv, GSList **flDest )
588     /// \todo fixme: Move these to some centralized location (Lauris)
589     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
590     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
593     // temporarily switch gettext encoding to locale, so that help messages can be output properly
594     gchar const *charset;
595     g_get_charset(&charset);
597     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
599     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
600     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
601     g_return_val_if_fail(ctx != NULL, 1);
603     /* Collect own arguments */
604     GSList *fl = sp_process_args(ctx);
605     poptFreeContext(ctx);
607     // now switch gettext back to UTF-8 (for GUI)
608     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
610     // Now let's see if the file list still holds up
611     if ( needToRecodeParams )
612     {
613         fl = fixupFilenameEncoding( fl );
614     }
616     // Check the globals for filename-fixup
617     if ( needToRecodeParams )
618     {
619         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
620         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
621         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
622     }
623     else
624     {
625         if ( sp_export_png )
626             sp_export_png_utf8 = g_strdup( sp_export_png );
627         if ( sp_export_svg )
628             sp_export_svg_utf8 = g_strdup( sp_export_svg );
629         if ( sp_global_printer )
630             sp_global_printer_utf8 = g_strdup( sp_global_printer );
631     }
633     // Return the list if wanted, else free it up.
634     if ( flDest ) {
635         *flDest = fl;
636         fl = 0;
637     } else {
638         while ( fl ) {
639             g_free( fl->data );
640             fl = g_slist_remove( fl, fl->data );
641         }
642     }
643     return 0;
646 static void
647 snooper(GdkEvent *event, gpointer /*data*/) {
648     if(inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
649     {
650         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
651         switch (event->type) {
652             case GDK_MOTION_NOTIFY:
653                 if(event->motion.state & mapping) {
654                     event->motion.state|=GDK_MOD1_MASK;
655                 }
656                 break;
657             case GDK_BUTTON_PRESS:
658                 if(event->button.state & mapping) {
659                     event->button.state|=GDK_MOD1_MASK;
660                 }
661                 break;
662              case GDK_KEY_PRESS:
663                  if(event->key.state & mapping) {
664                      event->key.state|=GDK_MOD1_MASK;
665                  }
666                  break;
667         default:
668             break;
669         }
670     }
671     gtk_main_do_event (event);
674 int
675 sp_main_gui(int argc, char const **argv)
677     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
679     GSList *fl = NULL;
680     int retVal = sp_common_main( argc, argv, &fl );
681     g_return_val_if_fail(retVal == 0, 1);
683     inkscape_gtk_stock_init();
685     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
687     Inkscape::Debug::log_display_config();
689     /* Set default icon */
690     gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
691     if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
692         gtk_window_set_default_icon_from_file(filename, NULL);
693     }
694     g_free (filename);
695     filename = 0;
697     gboolean create_new = TRUE;
699     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
700     inkscape_application_init(argv[0], true);
702     while (fl) {
703         if (sp_file_open((gchar *)fl->data,NULL)) {
704             create_new=FALSE;
705         }
706         fl = g_slist_remove(fl, fl->data);
707     }
708     if (create_new) {
709         sp_file_new_default();
710     }
712     Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
713     main_instance.run();
715 #ifdef WIN32
716     //We might not need anything here
717     //sp_win32_finish(); <-- this is a NOP func
718 #endif
720     return 0;
723 int
724 sp_main_console(int argc, char const **argv)
726     /* We are started in text mode */
728     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
729      * in a non-Gtk environment.  Used in libnrtype's
730      * FontInstance.cpp and FontFactory.cpp.
731      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
732      */
733     g_type_init();
734     char **argv2 = const_cast<char **>(argv);
735     gtk_init_check( &argc, &argv2 );
736     //setlocale(LC_ALL, "");
738     GSList *fl = NULL;
739     int retVal = sp_common_main( argc, argv, &fl );
740     g_return_val_if_fail(retVal == 0, 1);
742     if (fl == NULL) {
743         g_print("Nothing to do!\n");
744         exit(0);
745     }
747     inkscape_application_init(argv[0], false);
749     while (fl) {
750         SPDocument *doc;
752         doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
753         if (doc == NULL) {
754             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
755         }
756         if (doc == NULL) {
757             g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
758         } else {
759             if (sp_vacuum_defs) {
760                 vacuum_document(doc);
761             }
762             if (sp_vacuum_defs && !sp_export_svg) {
763                 // save under the name given in the command line
764                 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
765             }
766             if (sp_global_printer) {
767                 sp_print_document_to_file(doc, sp_global_printer);
768             }
769             if (sp_export_png || sp_export_id || sp_export_area_drawing) {
770                 sp_do_export_png(doc);
771             }
772             if (sp_export_svg) {
773                 Inkscape::XML::Document *rdoc;
774                 Inkscape::XML::Node *repr;
775                 rdoc = sp_repr_document_new("svg:svg");
776                 repr = rdoc->root();
777                 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
778                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
779             }
780             if (sp_export_ps) {
781                 do_export_ps(doc, sp_export_ps, "image/x-postscript");
782             }
783             if (sp_export_eps) {
784                 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
785             }
786             if (sp_export_pdf) {
787                 do_export_pdf(doc, sp_export_pdf, "application/pdf");
788             }
789 #ifdef WIN32
790             if (sp_export_emf) {
791                 do_export_emf(doc, sp_export_emf, "image/x-emf");
792             }
793 #endif //WIN32
794             if (sp_query_width || sp_query_height) {
795                 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
796             } else if (sp_query_x || sp_query_y) {
797                 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
798             }
799         }
801         fl = g_slist_remove(fl, fl->data);
802     }
804     inkscape_unref();
806     return 0;
809 static void
810 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
812     SPObject *o = NULL;
814     if (id) {
815         o = doc->getObjectById(id);
816         if (o) {
817             if (!SP_IS_ITEM (o)) {
818                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
819                 return;
820             }
821         } else {
822             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
823             return;
824         }
825     } else {
826         o = SP_DOCUMENT_ROOT(doc);
827     }
829     if (o) {
830         sp_document_ensure_up_to_date (doc);
831         SPItem *item = ((SPItem *) o);
833         // "true" SVG bbox for scripting
834         NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
835         if (area) {
836             Inkscape::SVGOStringStream os;
837             if (extent) {
838                 os << area->extent(axis);
839             } else {
840                 os << area->min()[axis];
841             }
842             g_print ("%s", os.str().c_str());
843         } else {
844             g_print("0");
845         }
846     }
850 static void
851 sp_do_export_png(SPDocument *doc)
853     const gchar *filename = NULL;
854     gdouble dpi = 0.0;
856     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
857         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
858     }
860     GSList *items = NULL;
862     NRRect area;
863     if (sp_export_id || sp_export_area_drawing) {
865         SPObject *o = NULL;
866         SPObject *o_area = NULL;
867         if (sp_export_id && sp_export_area_drawing) {
868             o = doc->getObjectById(sp_export_id);
869             o_area = SP_DOCUMENT_ROOT (doc);
870         } else if (sp_export_id) {
871             o = doc->getObjectById(sp_export_id);
872             o_area = o;
873         } else if (sp_export_area_drawing) {
874             o = SP_DOCUMENT_ROOT (doc);
875             o_area = o;
876         }
878         if (o) {
879             if (!SP_IS_ITEM (o)) {
880                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
881                 return;
882             }
884             items = g_slist_prepend (items, SP_ITEM(o));
886             if (sp_export_id_only) {
887                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
888             }
890             if (sp_export_use_hints) {
892                 // retrieve export filename hint
893                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
894                 if (fn_hint) {
895                     if (sp_export_png) {
896                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
897                         filename = sp_export_png;
898                     } else {
899                         filename = fn_hint;
900                     }
901                 } else {
902                     g_warning ("Export filename hint not found for the object.");
903                     filename = sp_export_png;
904                 }
906                 // retrieve export dpi hints
907                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
908                 if (dpi_hint) {
909                     if (sp_export_dpi || sp_export_width || sp_export_height) {
910                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
911                     } else {
912                         dpi = atof(dpi_hint);
913                     }
914                 } else {
915                     g_warning ("Export DPI hint not found for the object.");
916                 }
918             }
920             // write object bbox to area
921             sp_document_ensure_up_to_date (doc);
922             sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
923         } else {
924             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
925             return;
926         }
927     }
929     if (sp_export_area) {
930         /* Try to parse area (given in SVG pixels) */
931         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
932             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
933             return;
934         }
935         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
936             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
937             return;
938         }
939     } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
940         /* Export the whole canvas */
941         sp_document_ensure_up_to_date (doc);
942         area.x0 = SP_ROOT(doc->root)->x.computed;
943         area.y0 = SP_ROOT(doc->root)->y.computed;
944         area.x1 = area.x0 + sp_document_width (doc);
945         area.y1 = area.y0 + sp_document_height (doc);
946     }
948     // set filename and dpi from options, if not yet set from the hints
949     if (!filename) {
950         if (!sp_export_png) {
951             g_warning ("No export filename given and no filename hint. Nothing exported.");
952             return;
953         }
954         filename = sp_export_png;
955     }
957     if (sp_export_dpi && dpi == 0.0) {
958         dpi = atof(sp_export_dpi);
959         if ((dpi < 0.1) || (dpi > 10000.0)) {
960             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
961             return;
962         }
963         g_print("DPI: %g\n", dpi);
964     }
966     if (sp_export_area_snap) {
967         area.x0 = std::floor (area.x0);
968         area.y0 = std::floor (area.y0);
969         area.x1 = std::ceil (area.x1);
970         area.y1 = std::ceil (area.y1);
971     }
973     // default dpi
974     if (dpi == 0.0)
975         dpi = PX_PER_IN;
977     unsigned long int width = 0;
978     unsigned long int height = 0;
980     if (sp_export_width) {
981         width = strtoul(sp_export_width, NULL, 0);
982         if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
983             g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
984             return;
985         }
986         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
987     }
989     if (sp_export_height) {
990         height = strtoul(sp_export_height, NULL, 0);
991         if ((height < 1) || (height > PNG_UINT_31_MAX)) {
992             g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
993             return;
994         }
995         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
996     }
998     if (!sp_export_width) {
999         width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1000     }
1002     if (!sp_export_height) {
1003         height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1004     }
1006     guint32 bgcolor = 0x00000000;
1007     if (sp_export_background) {
1008         // override the page color
1009         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1010         bgcolor |= 0xff; // default is no opacity
1011     } else {
1012         // read from namedview
1013         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1014         if (nv && nv->attribute("pagecolor"))
1015             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1016         if (nv && nv->attribute("inkscape:pageopacity"))
1017             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1018     }
1020     if (sp_export_background_opacity) {
1021         // override opacity
1022         gfloat value;
1023         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1024             if (value > 1.0) {
1025                 value = CLAMP (value, 1.0f, 255.0f);
1026                 bgcolor &= (guint32) 0xffffff00;
1027                 bgcolor |= (guint32) floor(value);
1028             } else {
1029                 value = CLAMP (value, 0.0f, 1.0f);
1030                 bgcolor &= (guint32) 0xffffff00;
1031                 bgcolor |= SP_COLOR_F_TO_U(value);
1032             }
1033         }
1034     }
1036     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1038     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);
1040     g_print("Bitmap saved as: %s\n", filename);
1042     if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1043         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);
1044     } else {
1045         g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1046     }
1048     g_slist_free (items);
1052 /**
1053  *  Perform an export of either PS or EPS.
1054  *
1055  *  \param doc Document to export.
1056  *  \param uri URI to export to.
1057  *  \param mime MIME type to export as.
1058  */
1060 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1062     Inkscape::Extension::DB::OutputList o;
1063     Inkscape::Extension::db.get_output_list(o);
1064     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1065     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1066         i++;
1067     }
1069     if (i == o.end())
1070     {
1071         g_warning ("Could not find an extension to export this file.");
1072         return;
1073     }
1075     bool old_text_to_path = false;
1076     bool old_font_embedded = false;
1077     bool old_bbox_page = false;
1079     try {
1080         old_text_to_path = (*i)->get_param_bool("textToPath");
1081         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1082     }
1083     catch (...) {
1084         g_warning ("Could not set export-text-to-path option for this export.");
1085     }
1087     try {
1088         old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1089         (*i)->set_param_bool("fontEmbedded", sp_export_font);
1090     }
1091     catch (...) {
1092         g_warning ("Could not set export-font option for this export.");
1093     }
1095     try {
1096         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1097         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1098     }
1099     catch (...) {
1100         g_warning ("Could not set export-bbox-page option for this export.");
1101     }
1103     (*i)->save(doc, uri);
1105     try {
1106         (*i)->set_param_bool("textToPath", old_text_to_path);
1107         (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1108         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1109     }
1110     catch (...) {
1112     }
1115 /**
1116  *  Perform a PDF export
1117  *
1118  *  \param doc Document to export.
1119  *  \param uri URI to export to.
1120  *  \param mime MIME type to export as.
1121  */
1123 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1125     Inkscape::Extension::DB::OutputList o;
1126     Inkscape::Extension::db.get_output_list(o);
1127     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1128     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1129         i++;
1130     }
1132     if (i == o.end())
1133     {
1134         g_warning ("Could not find an extension to export this file.");
1135         return;
1136     }
1138     (*i)->save(doc, uri);
1141 #ifdef WIN32
1142 /**
1143  *  Export a document to EMF
1144  *
1145  *  \param doc Document to export.
1146  *  \param uri URI to export to.
1147  *  \param mime MIME type to export as (should be "image/x-emf")
1148  */
1150 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1152     Inkscape::Extension::DB::OutputList o;
1153     Inkscape::Extension::db.get_output_list(o);
1154     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1155     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1156         i++;
1157     }
1159     if (i == o.end())
1160     {
1161         g_warning ("Could not find an extension to export this file.");
1162         return;
1163     }
1165     (*i)->save(doc, uri);
1167 #endif //WIN32
1169 #ifdef WIN32
1170 bool replaceArgs( int& argc, char**& argv )
1172     bool worked = false;
1174 #ifdef REPLACEARGS_DEBUG
1175     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1176 #endif // REPLACEARGS_DEBUG
1178     wchar_t* line = GetCommandLineW();
1179     if ( line )
1180     {
1181 #ifdef REPLACEARGS_DEBUG
1182         {
1183             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1184             if ( utf8Line )
1185             {
1186                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1187                 {
1188                     char tmp[strlen(safe) + 32];
1189                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1190                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1191                 }
1192             }
1193         }
1194 #endif // REPLACEARGS_DEBUG
1196         int numArgs = 0;
1197         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1199 #ifdef REPLACEARGS_ANSI
1200 // test code for trying things on Win95/98/ME
1201         if ( !parsed )
1202         {
1203 #ifdef REPLACEARGS_DEBUG
1204             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1205 #endif // REPLACEARGS_DEBUG
1206             int lineLen = wcslen(line) + 1;
1207             wchar_t* lineDup = new wchar_t[lineLen];
1208             wcsncpy( lineDup, line, lineLen );
1210             int pos = 0;
1211             bool inQuotes = false;
1212             bool inWhitespace = true;
1213             std::vector<int> places;
1214             while ( lineDup[pos] )
1215             {
1216                 if ( inQuotes )
1217                 {
1218                     if ( lineDup[pos] == L'"' )
1219                     {
1220                         inQuotes = false;
1221                     }
1222                 }
1223                 else if ( lineDup[pos] == L'"' )
1224                 {
1225                     inQuotes = true;
1226                     inWhitespace = false;
1227                     places.push_back(pos);
1228                 }
1229                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1230                 {
1231                     if ( !inWhitespace )
1232                     {
1233                         inWhitespace = true;
1234                         lineDup[pos] = 0;
1235                     }
1236                 }
1237                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1238                 {
1239                     inWhitespace = false;
1240                     places.push_back(pos);
1241                 }
1242                 else
1243                 {
1244                     // consume
1245                 }
1246                 pos++;
1247             }
1248 #ifdef REPLACEARGS_DEBUG
1249             {
1250                 char tmp[256];
1251                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1252                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1253             }
1254 #endif // REPLACEARGS_DEBUG
1256             wchar_t** block = new wchar_t*[places.size()];
1257             int i = 0;
1258             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1259             {
1260                 block[i++] = &lineDup[*it];
1261             }
1262             parsed = block;
1263             numArgs = places.size();
1264         }
1265 #endif // REPLACEARGS_ANSI
1267         if ( parsed )
1268         {
1269             std::vector<wchar_t*>expandedArgs;
1270             if ( numArgs > 0 )
1271             {
1272                 expandedArgs.push_back( parsed[0] );
1273             }
1275             for ( int i1 = 1; i1 < numArgs; i1++ )
1276             {
1277                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1278                 wildcarded &= parsed[i1][0] != L'"';
1279                 wildcarded &= parsed[i1][0] != L'-';
1280                 if ( wildcarded )
1281                 {
1282 #ifdef REPLACEARGS_ANSI
1283                     WIN32_FIND_DATAA data = {0};
1284 #else
1285                     WIN32_FIND_DATAW data = {0};
1286 #endif // REPLACEARGS_ANSI
1288                     int baseLen = wcslen(parsed[i1]) + 2;
1289                     wchar_t* base = new wchar_t[baseLen];
1290                     wcsncpy( base, parsed[i1], baseLen );
1291                     wchar_t* last = wcsrchr( base, L'\\' );
1292                     if ( last )
1293                     {
1294                         last[1] = 0;
1295                     }
1296                     else
1297                     {
1298                         base[0] = 0;
1299                     }
1300                     baseLen = wcslen( base );
1302 #ifdef REPLACEARGS_ANSI
1303                     char target[MAX_PATH];
1304                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1305                     {
1306                         HANDLE hf = FindFirstFileA( target, &data );
1307 #else
1308                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1309 #endif // REPLACEARGS_ANSI
1310                         if ( hf != INVALID_HANDLE_VALUE )
1311                         {
1312                             BOOL found = TRUE;
1313                             do
1314                             {
1315 #ifdef REPLACEARGS_ANSI
1316                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1317                                 if ( howMany > 0 )
1318                                 {
1319                                     howMany += baseLen;
1320                                     wchar_t* tmp = new wchar_t[howMany + 1];
1321                                     wcsncpy( tmp, base, howMany + 1 );
1322                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1323                                     expandedArgs.push_back( tmp );
1324                                     found = FindNextFileA( hf, &data );
1325                                 }
1326 #else
1327                                 int howMany = wcslen(data.cFileName) + baseLen;
1328                                 wchar_t* tmp = new wchar_t[howMany + 1];
1329                                 wcsncpy( tmp, base, howMany + 1 );
1330                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1331                                 expandedArgs.push_back( tmp );
1332                                 found = FindNextFileW( hf, &data );
1333 #endif // REPLACEARGS_ANSI
1334                             } while ( found );
1336                             FindClose( hf );
1337                         }
1338                         else
1339                         {
1340                             expandedArgs.push_back( parsed[i1] );
1341                         }
1342 #ifdef REPLACEARGS_ANSI
1343                     }
1344 #endif // REPLACEARGS_ANSI
1346                     delete[] base;
1347                 }
1348                 else
1349                 {
1350                     expandedArgs.push_back( parsed[i1] );
1351                 }
1352             }
1354             {
1355                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1356                 int iz = 0;
1357                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1358                 {
1359                     block[iz++] = *it;
1360                 }
1361                 parsed = block;
1362                 numArgs = expandedArgs.size();
1363             }
1365             std::vector<gchar*> newArgs;
1366             for ( int i = 0; i < numArgs; i++ )
1367             {
1368                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1369                 if ( replacement )
1370                 {
1371 #ifdef REPLACEARGS_DEBUG
1372                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1374                     if ( safe2 )
1375                     {
1376                         {
1377                             char tmp[1024];
1378                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1379                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1380                         }
1381                         g_free( safe2 );
1382                     }
1383 #endif // REPLACEARGS_DEBUG
1385                     newArgs.push_back( replacement );
1386                 }
1387                 else
1388                 {
1389                     newArgs.push_back( blankParam );
1390                 }
1391             }
1393             // Now push our munged params to be the new argv and argc
1394             {
1395                 char** block = new char*[newArgs.size()];
1396                 int iz = 0;
1397                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1398                 {
1399                     block[iz++] = *it;
1400                 }
1401                 argv = block;
1402                 argc = newArgs.size();
1403                 worked = true;
1404             }
1405         }
1406 #ifdef REPLACEARGS_DEBUG
1407         else
1408         {
1409             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1410         }
1411 #endif // REPLACEARGS_DEBUG
1412     }
1413 #ifdef REPLACEARGS_DEBUG
1414     else
1415     {
1416         {
1417             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1418         }
1420         char* line2 = GetCommandLineA();
1421         if ( line2 )
1422         {
1423             gchar *safe = Inkscape::IO::sanitizeString(line2);
1424             {
1425                 {
1426                     char tmp[strlen(safe) + 32];
1427                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1428                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1429                 }
1430             }
1431         }
1432         else
1433         {
1434             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1435         }
1436     }
1437 #endif // REPLACEARGS_DEBUG
1439     return worked;
1441 #endif // WIN32
1443 static GSList *
1444 sp_process_args(poptContext ctx)
1446     GSList *fl = NULL;
1448     gint a;
1449     while ((a = poptGetNextOpt(ctx)) >= 0) {
1450         switch (a) {
1451             case SP_ARG_FILE: {
1452                 gchar const *fn = poptGetOptArg(ctx);
1453                 if (fn != NULL) {
1454                     fl = g_slist_append(fl, g_strdup(fn));
1455                 }
1456                 break;
1457             }
1458             case SP_ARG_VERSION: {
1459                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1460                 exit(0);
1461                 break;
1462             }
1463             case SP_ARG_EXTENSIONDIR: {
1464                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1465                 exit(0);
1466                 break;
1467             }
1468             case SP_ARG_VERB_LIST: {
1469                 // This really shouldn't go here, we should init the app.
1470                 // But, since we're just exiting in this path, there is
1471                 // no harm, and this is really a better place to put
1472                 // everything else.
1473                 Inkscape::Extension::init();
1474                 Inkscape::Verb::list();
1475                 exit(0);
1476                 break;
1477             }
1478             case SP_ARG_VERB:
1479             case SP_ARG_SELECT: {
1480                 gchar const *arg = poptGetOptArg(ctx);
1481                 if (arg != NULL) {
1482                     // printf("Adding in: %s\n", arg);
1483                     new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1484                 }
1485                 break;
1486             }
1487             default: {
1488                 break;
1489             }
1490         }
1491     }
1493     gchar const ** const args = poptGetArgs(ctx);
1494     if (args != NULL) {
1495         for (unsigned i = 0; args[i] != NULL; i++) {
1496             fl = g_slist_append(fl, g_strdup(args[i]));
1497         }
1498     }
1500     return fl;
1504 /*
1505   Local Variables:
1506   mode:c++
1507   c-file-style:"stroustrup"
1508   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1509   indent-tabs-mode:nil
1510   fill-column:99
1511   End:
1512 */
1513 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :