Code

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