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