Code

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