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