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 int
417 main(int argc, char **argv)
418 {
419 #ifdef HAVE_FPSETMASK
420 /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__. It's probably
421 safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
422 the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
423 fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
424 #endif
426 #ifdef ENABLE_NLS
427 #ifdef WIN32
428 RegistryTool rt;
429 rt.setPathInfo();
430 gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
431 bindtextdomain(GETTEXT_PACKAGE, pathBuf);
432 g_free(pathBuf);
433 #else
434 #ifdef ENABLE_BINRELOC
435 bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
436 #else
437 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
438 #endif
439 #endif
440 // Allow the user to override the locale directory by setting
441 // the environment variable INKSCAPE_LOCALEDIR.
442 char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
443 if (inkscape_localedir != NULL) {
444 bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
445 }
446 #endif
448 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
450 #ifdef ENABLE_NLS
451 textdomain(GETTEXT_PACKAGE);
452 #endif
454 LIBXML_TEST_VERSION
456 Inkscape::GC::init();
458 Inkscape::Debug::Logger::init();
460 gboolean use_gui;
461 #ifndef WIN32
462 use_gui = (getenv("DISPLAY") != NULL);
463 #else
464 /*
465 Set the current directory to the directory of the
466 executable. This seems redundant, but is needed for
467 when inkscape.exe is executed from another directory.
468 We use relative paths on win32.
469 HKCR\svgfile\shell\open\command is a good example
470 */
471 /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
472 char *homedir = g_path_get_dirname(argv[0]);
473 SetCurrentDirectory(homedir);
474 g_free(homedir);
476 use_gui = TRUE;
477 #endif
478 /* Test whether with/without GUI is forced */
479 for (int i = 1; i < argc; i++) {
480 if (!strcmp(argv[i], "-z")
481 || !strcmp(argv[i], "--without-gui")
482 || !strcmp(argv[i], "-p")
483 || !strncmp(argv[i], "--print", 7)
484 || !strcmp(argv[i], "-e")
485 || !strncmp(argv[i], "--export-png", 12)
486 || !strcmp(argv[i], "-l")
487 || !strncmp(argv[i], "--export-plain-svg", 12)
488 || !strcmp(argv[i], "-i")
489 || !strncmp(argv[i], "--export-area-drawing", 21)
490 || !strcmp(argv[i], "-D")
491 || !strncmp(argv[i], "--export-area-canvas", 20)
492 || !strcmp(argv[i], "-C")
493 || !strncmp(argv[i], "--export-id", 12)
494 || !strcmp(argv[i], "-P")
495 || !strncmp(argv[i], "--export-ps", 11)
496 || !strcmp(argv[i], "-E")
497 || !strncmp(argv[i], "--export-eps", 12)
498 || !strcmp(argv[i], "-A")
499 || !strncmp(argv[i], "--export-pdf", 12)
500 #ifdef WIN32
501 || !strcmp(argv[i], "-M")
502 || !strncmp(argv[i], "--export-emf", 12)
503 #endif //WIN32
504 || !strcmp(argv[i], "-W")
505 || !strncmp(argv[i], "--query-width", 13)
506 || !strcmp(argv[i], "-H")
507 || !strncmp(argv[i], "--query-height", 14)
508 || !strcmp(argv[i], "-S")
509 || !strncmp(argv[i], "--query-all", 11)
510 || !strcmp(argv[i], "-X")
511 || !strncmp(argv[i], "--query-x", 13)
512 || !strcmp(argv[i], "-Y")
513 || !strncmp(argv[i], "--query-y", 14)
514 || !strcmp(argv[i], "--vacuum-defs")
515 )
516 {
517 /* main_console handles any exports -- not the gui */
518 use_gui = FALSE;
519 break;
520 } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
521 use_gui = TRUE;
522 break;
523 }
524 }
526 #ifdef WIN32
527 #ifndef REPLACEARGS_ANSI
528 if ( PrintWin32::is_os_wide() )
529 #endif // REPLACEARGS_ANSI
530 {
531 // If the call fails, we'll need to convert charsets
532 needToRecodeParams = !replaceArgs( argc, argv );
533 }
534 #endif // WIN32
536 /// \todo Should this be a static object (see inkscape.cpp)?
537 Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
539 return app.run();
540 }
542 void fixupSingleFilename( gchar **orig, gchar **spare )
543 {
544 if ( orig && *orig && **orig ) {
545 GError *error = NULL;
546 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
547 if ( newFileName )
548 {
549 *orig = newFileName;
550 if ( spare ) {
551 *spare = newFileName;
552 }
553 // g_message("Set a replacement fixup");
554 }
555 }
556 }
558 GSList *fixupFilenameEncoding( GSList* fl )
559 {
560 GSList *newFl = NULL;
561 while ( fl ) {
562 gchar *fn = static_cast<gchar*>(fl->data);
563 fl = g_slist_remove( fl, fl->data );
564 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
565 if ( newFileName ) {
567 if ( 0 )
568 {
569 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
570 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
571 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
572 "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
573 gtk_dialog_run (GTK_DIALOG (w));
574 gtk_widget_destroy (w);
575 g_free(safeNewFn);
576 g_free(safeFn);
577 }
579 g_free( fn );
580 fn = newFileName;
581 newFileName = 0;
582 }
583 else
584 if ( 0 )
585 {
586 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
587 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
588 gtk_dialog_run (GTK_DIALOG (w));
589 gtk_widget_destroy (w);
590 g_free(safeFn);
591 }
592 newFl = g_slist_append( newFl, fn );
593 }
594 return newFl;
595 }
597 int sp_common_main( int argc, char const **argv, GSList **flDest )
598 {
599 /// \todo fixme: Move these to some centralized location (Lauris)
600 sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
601 sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
604 // temporarily switch gettext encoding to locale, so that help messages can be output properly
605 gchar const *charset;
606 g_get_charset(&charset);
608 bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
610 poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
611 poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
612 g_return_val_if_fail(ctx != NULL, 1);
614 /* Collect own arguments */
615 GSList *fl = sp_process_args(ctx);
616 poptFreeContext(ctx);
618 // now switch gettext back to UTF-8 (for GUI)
619 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
621 // Now let's see if the file list still holds up
622 if ( needToRecodeParams )
623 {
624 fl = fixupFilenameEncoding( fl );
625 }
627 // Check the globals for filename-fixup
628 if ( needToRecodeParams )
629 {
630 fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
631 fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
632 fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
633 }
634 else
635 {
636 if ( sp_export_png )
637 sp_export_png_utf8 = g_strdup( sp_export_png );
638 if ( sp_export_svg )
639 sp_export_svg_utf8 = g_strdup( sp_export_svg );
640 if ( sp_global_printer )
641 sp_global_printer_utf8 = g_strdup( sp_global_printer );
642 }
644 // Return the list if wanted, else free it up.
645 if ( flDest ) {
646 *flDest = fl;
647 fl = 0;
648 } else {
649 while ( fl ) {
650 g_free( fl->data );
651 fl = g_slist_remove( fl, fl->data );
652 }
653 }
654 return 0;
655 }
657 static void
658 snooper(GdkEvent *event, gpointer /*data*/) {
659 if(inkscape_mapalt()) /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
660 {
661 GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
662 switch (event->type) {
663 case GDK_MOTION_NOTIFY:
664 if(event->motion.state & mapping) {
665 event->motion.state|=GDK_MOD1_MASK;
666 }
667 break;
668 case GDK_BUTTON_PRESS:
669 if(event->button.state & mapping) {
670 event->button.state|=GDK_MOD1_MASK;
671 }
672 break;
673 case GDK_KEY_PRESS:
674 if(event->key.state & mapping) {
675 event->key.state|=GDK_MOD1_MASK;
676 }
677 break;
678 default:
679 break;
680 }
681 }
682 gtk_main_do_event (event);
683 }
685 int
686 sp_main_gui(int argc, char const **argv)
687 {
688 Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
690 GSList *fl = NULL;
691 int retVal = sp_common_main( argc, argv, &fl );
692 g_return_val_if_fail(retVal == 0, 1);
694 inkscape_gtk_stock_init();
696 gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
698 Inkscape::Debug::log_display_config();
700 /* Set default icon */
701 gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
702 if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
703 gtk_window_set_default_icon_from_file(filename, NULL);
704 }
705 g_free (filename);
706 filename = 0;
708 gboolean create_new = TRUE;
710 /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
711 inkscape_application_init(argv[0], true);
713 while (fl) {
714 if (sp_file_open((gchar *)fl->data,NULL)) {
715 create_new=FALSE;
716 }
717 fl = g_slist_remove(fl, fl->data);
718 }
719 if (create_new) {
720 sp_file_new_default();
721 }
723 Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
724 main_instance.run();
726 #ifdef WIN32
727 //We might not need anything here
728 //sp_win32_finish(); <-- this is a NOP func
729 #endif
731 return 0;
732 }
734 int
735 sp_main_console(int argc, char const **argv)
736 {
737 /* We are started in text mode */
739 /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
740 * in a non-Gtk environment. Used in libnrtype's
741 * FontInstance.cpp and FontFactory.cpp.
742 * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
743 */
744 g_type_init();
745 char **argv2 = const_cast<char **>(argv);
746 gtk_init_check( &argc, &argv2 );
747 //setlocale(LC_ALL, "");
749 GSList *fl = NULL;
750 int retVal = sp_common_main( argc, argv, &fl );
751 g_return_val_if_fail(retVal == 0, 1);
753 if (fl == NULL) {
754 g_print("Nothing to do!\n");
755 exit(0);
756 }
758 inkscape_application_init(argv[0], false);
760 while (fl) {
761 SPDocument *doc;
763 doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
764 if (doc == NULL) {
765 doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
766 }
767 if (doc == NULL) {
768 g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
769 } else {
770 if (sp_vacuum_defs) {
771 vacuum_document(doc);
772 }
773 if (sp_vacuum_defs && !sp_export_svg) {
774 // save under the name given in the command line
775 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
776 }
777 if (sp_global_printer) {
778 sp_print_document_to_file(doc, sp_global_printer);
779 }
780 if (sp_export_png || sp_export_id || sp_export_area_drawing) {
781 sp_do_export_png(doc);
782 }
783 if (sp_export_svg) {
784 Inkscape::XML::Document *rdoc;
785 Inkscape::XML::Node *repr;
786 rdoc = sp_repr_document_new("svg:svg");
787 repr = rdoc->root();
788 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
789 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
790 }
791 if (sp_export_ps) {
792 do_export_ps(doc, sp_export_ps, "image/x-postscript");
793 }
794 if (sp_export_eps) {
795 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
796 }
797 if (sp_export_pdf) {
798 do_export_pdf(doc, sp_export_pdf, "application/pdf");
799 }
800 #ifdef WIN32
801 if (sp_export_emf) {
802 do_export_emf(doc, sp_export_emf, "image/x-emf");
803 }
804 #endif //WIN32
805 if (sp_query_all) {
806 do_query_all (doc);
807 } else if (sp_query_width || sp_query_height) {
808 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
809 } else if (sp_query_x || sp_query_y) {
810 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
811 }
812 }
814 fl = g_slist_remove(fl, fl->data);
815 }
817 inkscape_unref();
819 return 0;
820 }
822 static void
823 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
824 {
825 SPObject *o = NULL;
827 if (id) {
828 o = doc->getObjectById(id);
829 if (o) {
830 if (!SP_IS_ITEM (o)) {
831 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
832 return;
833 }
834 } else {
835 g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
836 return;
837 }
838 } else {
839 o = SP_DOCUMENT_ROOT(doc);
840 }
842 if (o) {
843 sp_document_ensure_up_to_date (doc);
844 SPItem *item = ((SPItem *) o);
846 // "true" SVG bbox for scripting
847 NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
848 if (area) {
849 Inkscape::SVGOStringStream os;
850 if (extent) {
851 os << area->extent(axis);
852 } else {
853 os << area->min()[axis];
854 }
855 g_print ("%s", os.str().c_str());
856 } else {
857 g_print("0");
858 }
859 }
860 }
862 static void
863 do_query_all (SPDocument *doc)
864 {
865 SPObject *o = NULL;
867 o = SP_DOCUMENT_ROOT(doc);
869 if (o) {
870 sp_document_ensure_up_to_date (doc);
871 do_query_all_recurse(o);
872 }
873 }
875 static void
876 do_query_all_recurse (SPObject *o)
877 {
878 SPItem *item = ((SPItem *) o);
879 if (o->id && SP_IS_ITEM(item)) {
880 NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
881 if (area) {
882 Inkscape::SVGOStringStream os;
883 os << o->id;
884 os << "," << area->min()[NR::X];
885 os << "," << area->min()[NR::Y];
886 os << "," << area->extent(NR::X);
887 os << "," << area->extent(NR::Y);
888 g_print ("%s\n", os.str().c_str());
889 }
890 }
892 SPObject *child = o->children;
893 while (child) {
894 do_query_all_recurse (child);
895 child = child->next;
896 }
897 }
900 static void
901 sp_do_export_png(SPDocument *doc)
902 {
903 const gchar *filename = NULL;
904 gdouble dpi = 0.0;
906 if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
907 g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
908 }
910 GSList *items = NULL;
912 NRRect area;
913 if (sp_export_id || sp_export_area_drawing) {
915 SPObject *o = NULL;
916 SPObject *o_area = NULL;
917 if (sp_export_id && sp_export_area_drawing) {
918 o = doc->getObjectById(sp_export_id);
919 o_area = SP_DOCUMENT_ROOT (doc);
920 } else if (sp_export_id) {
921 o = doc->getObjectById(sp_export_id);
922 o_area = o;
923 } else if (sp_export_area_drawing) {
924 o = SP_DOCUMENT_ROOT (doc);
925 o_area = o;
926 }
928 if (o) {
929 if (!SP_IS_ITEM (o)) {
930 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
931 return;
932 }
934 items = g_slist_prepend (items, SP_ITEM(o));
936 if (sp_export_id_only) {
937 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
938 }
940 if (sp_export_use_hints) {
942 // retrieve export filename hint
943 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
944 if (fn_hint) {
945 if (sp_export_png) {
946 g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
947 filename = sp_export_png;
948 } else {
949 filename = fn_hint;
950 }
951 } else {
952 g_warning ("Export filename hint not found for the object.");
953 filename = sp_export_png;
954 }
956 // retrieve export dpi hints
957 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
958 if (dpi_hint) {
959 if (sp_export_dpi || sp_export_width || sp_export_height) {
960 g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
961 } else {
962 dpi = atof(dpi_hint);
963 }
964 } else {
965 g_warning ("Export DPI hint not found for the object.");
966 }
968 }
970 // write object bbox to area
971 sp_document_ensure_up_to_date (doc);
972 sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
973 } else {
974 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
975 return;
976 }
977 }
979 if (sp_export_area) {
980 /* Try to parse area (given in SVG pixels) */
981 if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
982 g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
983 return;
984 }
985 if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
986 g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
987 return;
988 }
989 } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
990 /* Export the whole canvas */
991 sp_document_ensure_up_to_date (doc);
992 area.x0 = SP_ROOT(doc->root)->x.computed;
993 area.y0 = SP_ROOT(doc->root)->y.computed;
994 area.x1 = area.x0 + sp_document_width (doc);
995 area.y1 = area.y0 + sp_document_height (doc);
996 }
998 // set filename and dpi from options, if not yet set from the hints
999 if (!filename) {
1000 if (!sp_export_png) {
1001 g_warning ("No export filename given and no filename hint. Nothing exported.");
1002 return;
1003 }
1004 filename = sp_export_png;
1005 }
1007 if (sp_export_dpi && dpi == 0.0) {
1008 dpi = atof(sp_export_dpi);
1009 if ((dpi < 0.1) || (dpi > 10000.0)) {
1010 g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1011 return;
1012 }
1013 g_print("DPI: %g\n", dpi);
1014 }
1016 if (sp_export_area_snap) {
1017 area.x0 = std::floor (area.x0);
1018 area.y0 = std::floor (area.y0);
1019 area.x1 = std::ceil (area.x1);
1020 area.y1 = std::ceil (area.y1);
1021 }
1023 // default dpi
1024 if (dpi == 0.0)
1025 dpi = PX_PER_IN;
1027 unsigned long int width = 0;
1028 unsigned long int height = 0;
1030 if (sp_export_width) {
1031 width = strtoul(sp_export_width, NULL, 0);
1032 if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1033 g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1034 return;
1035 }
1036 dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1037 }
1039 if (sp_export_height) {
1040 height = strtoul(sp_export_height, NULL, 0);
1041 if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1042 g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1043 return;
1044 }
1045 dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1046 }
1048 if (!sp_export_width) {
1049 width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1050 }
1052 if (!sp_export_height) {
1053 height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1054 }
1056 guint32 bgcolor = 0x00000000;
1057 if (sp_export_background) {
1058 // override the page color
1059 bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1060 bgcolor |= 0xff; // default is no opacity
1061 } else {
1062 // read from namedview
1063 Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1064 if (nv && nv->attribute("pagecolor"))
1065 bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1066 if (nv && nv->attribute("inkscape:pageopacity"))
1067 bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1068 }
1070 if (sp_export_background_opacity) {
1071 // override opacity
1072 gfloat value;
1073 if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1074 if (value > 1.0) {
1075 value = CLAMP (value, 1.0f, 255.0f);
1076 bgcolor &= (guint32) 0xffffff00;
1077 bgcolor |= (guint32) floor(value);
1078 } else {
1079 value = CLAMP (value, 0.0f, 1.0f);
1080 bgcolor &= (guint32) 0xffffff00;
1081 bgcolor |= SP_COLOR_F_TO_U(value);
1082 }
1083 }
1084 }
1086 g_print("Background RRGGBBAA: %08x\n", bgcolor);
1088 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);
1090 g_print("Bitmap saved as: %s\n", filename);
1092 if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1093 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);
1094 } else {
1095 g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1096 }
1098 g_slist_free (items);
1099 }
1102 /**
1103 * Perform an export of either PS or EPS.
1104 *
1105 * \param doc Document to export.
1106 * \param uri URI to export to.
1107 * \param mime MIME type to export as.
1108 */
1110 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1111 {
1112 Inkscape::Extension::DB::OutputList o;
1113 Inkscape::Extension::db.get_output_list(o);
1114 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1115 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1116 i++;
1117 }
1119 if (i == o.end())
1120 {
1121 g_warning ("Could not find an extension to export this file.");
1122 return;
1123 }
1125 bool old_text_to_path = false;
1126 bool old_font_embedded = false;
1127 bool old_bbox_page = false;
1129 try {
1130 old_text_to_path = (*i)->get_param_bool("textToPath");
1131 (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1132 }
1133 catch (...) {
1134 g_warning ("Could not set export-text-to-path option for this export.");
1135 }
1137 try {
1138 old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1139 (*i)->set_param_bool("fontEmbedded", sp_export_font);
1140 }
1141 catch (...) {
1142 g_warning ("Could not set export-font option for this export.");
1143 }
1145 try {
1146 old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1147 (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1148 }
1149 catch (...) {
1150 g_warning ("Could not set export-bbox-page option for this export.");
1151 }
1153 (*i)->save(doc, uri);
1155 try {
1156 (*i)->set_param_bool("textToPath", old_text_to_path);
1157 (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1158 (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1159 }
1160 catch (...) {
1162 }
1163 }
1165 /**
1166 * Perform a PDF export
1167 *
1168 * \param doc Document to export.
1169 * \param uri URI to export to.
1170 * \param mime MIME type to export as.
1171 */
1173 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1174 {
1175 Inkscape::Extension::DB::OutputList o;
1176 Inkscape::Extension::db.get_output_list(o);
1177 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1178 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1179 i++;
1180 }
1182 if (i == o.end())
1183 {
1184 g_warning ("Could not find an extension to export this file.");
1185 return;
1186 }
1188 (*i)->save(doc, uri);
1189 }
1191 #ifdef WIN32
1192 /**
1193 * Export a document to EMF
1194 *
1195 * \param doc Document to export.
1196 * \param uri URI to export to.
1197 * \param mime MIME type to export as (should be "image/x-emf")
1198 */
1200 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1201 {
1202 Inkscape::Extension::DB::OutputList o;
1203 Inkscape::Extension::db.get_output_list(o);
1204 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1205 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1206 i++;
1207 }
1209 if (i == o.end())
1210 {
1211 g_warning ("Could not find an extension to export this file.");
1212 return;
1213 }
1215 (*i)->save(doc, uri);
1216 }
1217 #endif //WIN32
1219 #ifdef WIN32
1220 bool replaceArgs( int& argc, char**& argv )
1221 {
1222 bool worked = false;
1224 #ifdef REPLACEARGS_DEBUG
1225 MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1226 #endif // REPLACEARGS_DEBUG
1228 wchar_t* line = GetCommandLineW();
1229 if ( line )
1230 {
1231 #ifdef REPLACEARGS_DEBUG
1232 {
1233 gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1234 if ( utf8Line )
1235 {
1236 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1237 {
1238 char tmp[strlen(safe) + 32];
1239 snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1240 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1241 }
1242 }
1243 }
1244 #endif // REPLACEARGS_DEBUG
1246 int numArgs = 0;
1247 wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1249 #ifdef REPLACEARGS_ANSI
1250 // test code for trying things on Win95/98/ME
1251 if ( !parsed )
1252 {
1253 #ifdef REPLACEARGS_DEBUG
1254 MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1255 #endif // REPLACEARGS_DEBUG
1256 int lineLen = wcslen(line) + 1;
1257 wchar_t* lineDup = new wchar_t[lineLen];
1258 wcsncpy( lineDup, line, lineLen );
1260 int pos = 0;
1261 bool inQuotes = false;
1262 bool inWhitespace = true;
1263 std::vector<int> places;
1264 while ( lineDup[pos] )
1265 {
1266 if ( inQuotes )
1267 {
1268 if ( lineDup[pos] == L'"' )
1269 {
1270 inQuotes = false;
1271 }
1272 }
1273 else if ( lineDup[pos] == L'"' )
1274 {
1275 inQuotes = true;
1276 inWhitespace = false;
1277 places.push_back(pos);
1278 }
1279 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1280 {
1281 if ( !inWhitespace )
1282 {
1283 inWhitespace = true;
1284 lineDup[pos] = 0;
1285 }
1286 }
1287 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1288 {
1289 inWhitespace = false;
1290 places.push_back(pos);
1291 }
1292 else
1293 {
1294 // consume
1295 }
1296 pos++;
1297 }
1298 #ifdef REPLACEARGS_DEBUG
1299 {
1300 char tmp[256];
1301 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1302 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1303 }
1304 #endif // REPLACEARGS_DEBUG
1306 wchar_t** block = new wchar_t*[places.size()];
1307 int i = 0;
1308 for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1309 {
1310 block[i++] = &lineDup[*it];
1311 }
1312 parsed = block;
1313 numArgs = places.size();
1314 }
1315 #endif // REPLACEARGS_ANSI
1317 if ( parsed )
1318 {
1319 std::vector<wchar_t*>expandedArgs;
1320 if ( numArgs > 0 )
1321 {
1322 expandedArgs.push_back( parsed[0] );
1323 }
1325 for ( int i1 = 1; i1 < numArgs; i1++ )
1326 {
1327 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1328 wildcarded &= parsed[i1][0] != L'"';
1329 wildcarded &= parsed[i1][0] != L'-';
1330 if ( wildcarded )
1331 {
1332 #ifdef REPLACEARGS_ANSI
1333 WIN32_FIND_DATAA data = {0};
1334 #else
1335 WIN32_FIND_DATAW data = {0};
1336 #endif // REPLACEARGS_ANSI
1338 int baseLen = wcslen(parsed[i1]) + 2;
1339 wchar_t* base = new wchar_t[baseLen];
1340 wcsncpy( base, parsed[i1], baseLen );
1341 wchar_t* last = wcsrchr( base, L'\\' );
1342 if ( last )
1343 {
1344 last[1] = 0;
1345 }
1346 else
1347 {
1348 base[0] = 0;
1349 }
1350 baseLen = wcslen( base );
1352 #ifdef REPLACEARGS_ANSI
1353 char target[MAX_PATH];
1354 if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1355 {
1356 HANDLE hf = FindFirstFileA( target, &data );
1357 #else
1358 HANDLE hf = FindFirstFileW( parsed[i1], &data );
1359 #endif // REPLACEARGS_ANSI
1360 if ( hf != INVALID_HANDLE_VALUE )
1361 {
1362 BOOL found = TRUE;
1363 do
1364 {
1365 #ifdef REPLACEARGS_ANSI
1366 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1367 if ( howMany > 0 )
1368 {
1369 howMany += baseLen;
1370 wchar_t* tmp = new wchar_t[howMany + 1];
1371 wcsncpy( tmp, base, howMany + 1 );
1372 MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1373 expandedArgs.push_back( tmp );
1374 found = FindNextFileA( hf, &data );
1375 }
1376 #else
1377 int howMany = wcslen(data.cFileName) + baseLen;
1378 wchar_t* tmp = new wchar_t[howMany + 1];
1379 wcsncpy( tmp, base, howMany + 1 );
1380 wcsncat( tmp, data.cFileName, howMany + 1 );
1381 expandedArgs.push_back( tmp );
1382 found = FindNextFileW( hf, &data );
1383 #endif // REPLACEARGS_ANSI
1384 } while ( found );
1386 FindClose( hf );
1387 }
1388 else
1389 {
1390 expandedArgs.push_back( parsed[i1] );
1391 }
1392 #ifdef REPLACEARGS_ANSI
1393 }
1394 #endif // REPLACEARGS_ANSI
1396 delete[] base;
1397 }
1398 else
1399 {
1400 expandedArgs.push_back( parsed[i1] );
1401 }
1402 }
1404 {
1405 wchar_t** block = new wchar_t*[expandedArgs.size()];
1406 int iz = 0;
1407 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1408 {
1409 block[iz++] = *it;
1410 }
1411 parsed = block;
1412 numArgs = expandedArgs.size();
1413 }
1415 std::vector<gchar*> newArgs;
1416 for ( int i = 0; i < numArgs; i++ )
1417 {
1418 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1419 if ( replacement )
1420 {
1421 #ifdef REPLACEARGS_DEBUG
1422 gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1424 if ( safe2 )
1425 {
1426 {
1427 char tmp[1024];
1428 snprintf( tmp, sizeof(tmp), " [%2d] = '%s'", i, safe2 );
1429 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1430 }
1431 g_free( safe2 );
1432 }
1433 #endif // REPLACEARGS_DEBUG
1435 newArgs.push_back( replacement );
1436 }
1437 else
1438 {
1439 newArgs.push_back( blankParam );
1440 }
1441 }
1443 // Now push our munged params to be the new argv and argc
1444 {
1445 char** block = new char*[newArgs.size()];
1446 int iz = 0;
1447 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1448 {
1449 block[iz++] = *it;
1450 }
1451 argv = block;
1452 argc = newArgs.size();
1453 worked = true;
1454 }
1455 }
1456 #ifdef REPLACEARGS_DEBUG
1457 else
1458 {
1459 MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1460 }
1461 #endif // REPLACEARGS_DEBUG
1462 }
1463 #ifdef REPLACEARGS_DEBUG
1464 else
1465 {
1466 {
1467 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1468 }
1470 char* line2 = GetCommandLineA();
1471 if ( line2 )
1472 {
1473 gchar *safe = Inkscape::IO::sanitizeString(line2);
1474 {
1475 {
1476 char tmp[strlen(safe) + 32];
1477 snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1478 MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1479 }
1480 }
1481 }
1482 else
1483 {
1484 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1485 }
1486 }
1487 #endif // REPLACEARGS_DEBUG
1489 return worked;
1490 }
1491 #endif // WIN32
1493 static GSList *
1494 sp_process_args(poptContext ctx)
1495 {
1496 GSList *fl = NULL;
1498 gint a;
1499 while ((a = poptGetNextOpt(ctx)) >= 0) {
1500 switch (a) {
1501 case SP_ARG_FILE: {
1502 gchar const *fn = poptGetOptArg(ctx);
1503 if (fn != NULL) {
1504 fl = g_slist_append(fl, g_strdup(fn));
1505 }
1506 break;
1507 }
1508 case SP_ARG_VERSION: {
1509 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1510 exit(0);
1511 break;
1512 }
1513 case SP_ARG_EXTENSIONDIR: {
1514 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1515 exit(0);
1516 break;
1517 }
1518 case SP_ARG_VERB_LIST: {
1519 // This really shouldn't go here, we should init the app.
1520 // But, since we're just exiting in this path, there is
1521 // no harm, and this is really a better place to put
1522 // everything else.
1523 Inkscape::Extension::init();
1524 Inkscape::Verb::list();
1525 exit(0);
1526 break;
1527 }
1528 case SP_ARG_VERB:
1529 case SP_ARG_SELECT: {
1530 gchar const *arg = poptGetOptArg(ctx);
1531 if (arg != NULL) {
1532 // printf("Adding in: %s\n", arg);
1533 new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1534 }
1535 break;
1536 }
1537 default: {
1538 break;
1539 }
1540 }
1541 }
1543 gchar const ** const args = poptGetArgs(ctx);
1544 if (args != NULL) {
1545 for (unsigned i = 0; args[i] != NULL; i++) {
1546 fl = g_slist_append(fl, g_strdup(args[i]));
1547 }
1548 }
1550 return fl;
1551 }
1554 /*
1555 Local Variables:
1556 mode:c++
1557 c-file-style:"stroustrup"
1558 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1559 indent-tabs-mode:nil
1560 fill-column:99
1561 End:
1562 */
1563 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :