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_ID,
152 SP_ARG_VERSION,
153 SP_ARG_VACUUM_DEFS,
154 SP_ARG_VERB_LIST,
155 SP_ARG_VERB,
156 SP_ARG_SELECT,
157 SP_ARG_LAST
158 };
160 int sp_main_gui(int argc, char const **argv);
161 int sp_main_console(int argc, char const **argv);
162 static void sp_do_export_png(SPDocument *doc);
163 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
164 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const *mime);
165 #ifdef WIN32
166 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
167 #endif //WIN32
168 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
171 static gchar *sp_global_printer = NULL;
172 static gchar *sp_export_png = NULL;
173 static gchar *sp_export_dpi = NULL;
174 static gchar *sp_export_area = NULL;
175 static gboolean sp_export_area_drawing = FALSE;
176 static gboolean sp_export_area_canvas = FALSE;
177 static gchar *sp_export_width = NULL;
178 static gchar *sp_export_height = NULL;
179 static gchar *sp_export_id = NULL;
180 static gchar *sp_export_background = NULL;
181 static gchar *sp_export_background_opacity = NULL;
182 static gboolean sp_export_area_snap = FALSE;
183 static gboolean sp_export_use_hints = FALSE;
184 static gboolean sp_export_id_only = FALSE;
185 static gchar *sp_export_svg = NULL;
186 static gchar *sp_export_ps = NULL;
187 static gchar *sp_export_eps = NULL;
188 static gchar *sp_export_pdf = NULL;
189 #ifdef WIN32
190 static gchar *sp_export_emf = NULL;
191 #endif //WIN32
192 static gboolean sp_export_text_to_path = FALSE;
193 static gboolean sp_export_font = FALSE;
194 static gboolean sp_export_bbox_page = FALSE;
195 static gboolean sp_query_x = FALSE;
196 static gboolean sp_query_y = FALSE;
197 static gboolean sp_query_width = FALSE;
198 static gboolean sp_query_height = FALSE;
199 static gchar *sp_query_id = NULL;
200 static int sp_new_gui = FALSE;
201 static gboolean sp_vacuum_defs = FALSE;
203 static gchar *sp_export_png_utf8 = NULL;
204 static gchar *sp_export_svg_utf8 = NULL;
205 static gchar *sp_global_printer_utf8 = NULL;
207 #ifdef WIN32
208 static bool replaceArgs( int& argc, char**& argv );
209 #endif
210 static GSList *sp_process_args(poptContext ctx);
211 struct poptOption options[] = {
212 {"version", 'V',
213 POPT_ARG_NONE, NULL, SP_ARG_VERSION,
214 N_("Print the Inkscape version number"),
215 NULL},
217 {"without-gui", 'z',
218 POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
219 N_("Do not use X server (only process files from console)"),
220 NULL},
222 {"with-gui", 'g',
223 POPT_ARG_NONE, NULL, SP_ARG_GUI,
224 N_("Try to use X server (even if $DISPLAY is not set)"),
225 NULL},
227 {"file", 'f',
228 POPT_ARG_STRING, NULL, SP_ARG_FILE,
229 N_("Open specified document(s) (option string may be excluded)"),
230 N_("FILENAME")},
232 {"print", 'p',
233 POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
234 N_("Print document(s) to specified output file (use '| program' for pipe)"),
235 N_("FILENAME")},
237 {"export-png", 'e',
238 POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
239 N_("Export document to a PNG file"),
240 N_("FILENAME")},
242 {"export-dpi", 'd',
243 POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
244 N_("The resolution used for exporting SVG into bitmap (default 90)"),
245 N_("DPI")},
247 {"export-area", 'a',
248 POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
249 N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
250 N_("x0:y0:x1:y1")},
252 {"export-area-drawing", 'D',
253 POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
254 N_("Exported area is the entire drawing (not canvas)"),
255 NULL},
257 {"export-area-canvas", 'C',
258 POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
259 N_("Exported area is the entire canvas"),
260 NULL},
262 {"export-area-snap", 0,
263 POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
264 N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
265 NULL},
267 {"export-width", 'w',
268 POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
269 N_("The width of exported bitmap in pixels (overrides export-dpi)"),
270 N_("WIDTH")},
272 {"export-height", 'h',
273 POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
274 N_("The height of exported bitmap in pixels (overrides export-dpi)"),
275 N_("HEIGHT")},
277 {"export-id", 'i',
278 POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
279 N_("The ID of the object to export"),
280 N_("ID")},
282 {"export-id-only", 'j',
283 POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
284 // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
285 // See "man inkscape" for details.
286 N_("Export just the object with export-id, hide all others (only with export-id)"),
287 NULL},
289 {"export-use-hints", 't',
290 POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
291 N_("Use stored filename and DPI hints when exporting (only with export-id)"),
292 NULL},
294 {"export-background", 'b',
295 POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
296 N_("Background color of exported bitmap (any SVG-supported color string)"),
297 N_("COLOR")},
299 {"export-background-opacity", 'y',
300 POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
301 N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
302 N_("VALUE")},
304 {"export-plain-svg", 'l',
305 POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
306 N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
307 N_("FILENAME")},
309 {"export-ps", 'P',
310 POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
311 N_("Export document to a PS file"),
312 N_("FILENAME")},
314 {"export-eps", 'E',
315 POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
316 N_("Export document to an EPS file"),
317 N_("FILENAME")},
319 {"export-pdf", 'A',
320 POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
321 N_("Export document to a PDF file"),
322 N_("FILENAME")},
324 #ifdef WIN32
325 {"export-emf", 'M',
326 POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
327 N_("Export document to an Enhanced Metafile (EMF) File"),
328 N_("FILENAME")},
329 #endif //WIN32
331 {"export-text-to-path", 'T',
332 POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
333 N_("Convert text object to paths on export (EPS)"),
334 NULL},
336 {"export-embed-fonts", 'F',
337 POPT_ARG_NONE, &sp_export_font, SP_ARG_EXPORT_FONT,
338 N_("Embed fonts on export (Type 1 only) (EPS)"),
339 NULL},
341 {"export-bbox-page", 'B',
342 POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
343 N_("Export files with the bounding box set to the page size (EPS)"),
344 NULL},
346 {"query-x", 'X',
347 POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
348 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
349 N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
350 NULL},
352 {"query-y", 'Y',
353 POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
354 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
355 N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
356 NULL},
358 {"query-width", 'W',
359 POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
360 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
361 N_("Query the width of the drawing or, if specified, of the object with --query-id"),
362 NULL},
364 {"query-height", 'H',
365 POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
366 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
367 N_("Query the height of the drawing or, if specified, of the object with --query-id"),
368 NULL},
370 {"query-id", 'I',
371 POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
372 N_("The ID of the object whose dimensions are queried"),
373 N_("ID")},
375 {"extension-directory", 'x',
376 POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
377 // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
378 N_("Print out the extension directory and exit"),
379 NULL},
381 {"vacuum-defs", 0,
382 POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
383 N_("Remove unused definitions from the defs section(s) of the document"),
384 NULL},
386 {"verb-list", 0,
387 POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
388 N_("List the IDs of all the verbs in Inkscape"),
389 NULL},
391 {"verb", 0,
392 POPT_ARG_STRING, NULL, SP_ARG_VERB,
393 N_("Verb to call when Inkscape opens."),
394 N_("VERB-ID")},
396 {"select", 0,
397 POPT_ARG_STRING, NULL, SP_ARG_SELECT,
398 N_("Object ID to select when Inkscape opens."),
399 N_("OBJECT-ID")},
401 POPT_AUTOHELP POPT_TABLEEND
402 };
404 static bool needToRecodeParams = true;
405 gchar* blankParam = "";
407 int
408 main(int argc, char **argv)
409 {
410 #ifdef HAVE_FPSETMASK
411 /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__. It's probably
412 safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
413 the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
414 fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
415 #endif
417 #ifdef ENABLE_NLS
418 #ifdef WIN32
419 RegistryTool rt;
420 rt.setPathInfo();
421 gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
422 bindtextdomain(GETTEXT_PACKAGE, pathBuf);
423 g_free(pathBuf);
424 #else
425 #ifdef ENABLE_BINRELOC
426 bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
427 #else
428 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
429 #endif
430 #endif
431 // Allow the user to override the locale directory by setting
432 // the environment variable INKSCAPE_LOCALEDIR.
433 char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
434 if (inkscape_localedir != NULL) {
435 bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
436 }
437 #endif
439 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
441 #ifdef ENABLE_NLS
442 textdomain(GETTEXT_PACKAGE);
443 #endif
445 LIBXML_TEST_VERSION
447 Inkscape::GC::init();
449 Inkscape::Debug::Logger::init();
451 gboolean use_gui;
452 #ifndef WIN32
453 use_gui = (getenv("DISPLAY") != NULL);
454 #else
455 /*
456 Set the current directory to the directory of the
457 executable. This seems redundant, but is needed for
458 when inkscape.exe is executed from another directory.
459 We use relative paths on win32.
460 HKCR\svgfile\shell\open\command is a good example
461 */
462 /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
463 char *homedir = g_path_get_dirname(argv[0]);
464 SetCurrentDirectory(homedir);
465 g_free(homedir);
467 use_gui = TRUE;
468 #endif
469 /* Test whether with/without GUI is forced */
470 for (int i = 1; i < argc; i++) {
471 if (!strcmp(argv[i], "-z")
472 || !strcmp(argv[i], "--without-gui")
473 || !strcmp(argv[i], "-p")
474 || !strncmp(argv[i], "--print", 7)
475 || !strcmp(argv[i], "-e")
476 || !strncmp(argv[i], "--export-png", 12)
477 || !strcmp(argv[i], "-l")
478 || !strncmp(argv[i], "--export-plain-svg", 12)
479 || !strcmp(argv[i], "-i")
480 || !strncmp(argv[i], "--export-area-drawing", 21)
481 || !strcmp(argv[i], "-D")
482 || !strncmp(argv[i], "--export-area-canvas", 20)
483 || !strcmp(argv[i], "-C")
484 || !strncmp(argv[i], "--export-id", 12)
485 || !strcmp(argv[i], "-P")
486 || !strncmp(argv[i], "--export-ps", 11)
487 || !strcmp(argv[i], "-E")
488 || !strncmp(argv[i], "--export-eps", 12)
489 || !strcmp(argv[i], "-A")
490 || !strncmp(argv[i], "--export-pdf", 12)
491 #ifdef WIN32
492 || !strcmp(argv[i], "-M")
493 || !strncmp(argv[i], "--export-emf", 12)
494 #endif //WIN32
495 || !strcmp(argv[i], "-W")
496 || !strncmp(argv[i], "--query-width", 13)
497 || !strcmp(argv[i], "-H")
498 || !strncmp(argv[i], "--query-height", 14)
499 || !strcmp(argv[i], "-X")
500 || !strncmp(argv[i], "--query-x", 13)
501 || !strcmp(argv[i], "-Y")
502 || !strncmp(argv[i], "--query-y", 14)
503 || !strcmp(argv[i], "--vacuum-defs")
504 )
505 {
506 /* main_console handles any exports -- not the gui */
507 use_gui = FALSE;
508 break;
509 } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
510 use_gui = TRUE;
511 break;
512 }
513 }
515 #ifdef WIN32
516 #ifndef REPLACEARGS_ANSI
517 if ( PrintWin32::is_os_wide() )
518 #endif // REPLACEARGS_ANSI
519 {
520 // If the call fails, we'll need to convert charsets
521 needToRecodeParams = !replaceArgs( argc, argv );
522 }
523 #endif // WIN32
525 /// \todo Should this be a static object (see inkscape.cpp)?
526 Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
528 return app.run();
529 }
531 void fixupSingleFilename( gchar **orig, gchar **spare )
532 {
533 if ( orig && *orig && **orig ) {
534 GError *error = NULL;
535 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
536 if ( newFileName )
537 {
538 *orig = newFileName;
539 if ( spare ) {
540 *spare = newFileName;
541 }
542 // g_message("Set a replacement fixup");
543 }
544 }
545 }
547 GSList *fixupFilenameEncoding( GSList* fl )
548 {
549 GSList *newFl = NULL;
550 while ( fl ) {
551 gchar *fn = static_cast<gchar*>(fl->data);
552 fl = g_slist_remove( fl, fl->data );
553 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
554 if ( newFileName ) {
556 if ( 0 )
557 {
558 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
559 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
560 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
561 "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
562 gtk_dialog_run (GTK_DIALOG (w));
563 gtk_widget_destroy (w);
564 g_free(safeNewFn);
565 g_free(safeFn);
566 }
568 g_free( fn );
569 fn = newFileName;
570 newFileName = 0;
571 }
572 else
573 if ( 0 )
574 {
575 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
576 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
577 gtk_dialog_run (GTK_DIALOG (w));
578 gtk_widget_destroy (w);
579 g_free(safeFn);
580 }
581 newFl = g_slist_append( newFl, fn );
582 }
583 return newFl;
584 }
586 int sp_common_main( int argc, char const **argv, GSList **flDest )
587 {
588 /// \todo fixme: Move these to some centralized location (Lauris)
589 sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
590 sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
593 // temporarily switch gettext encoding to locale, so that help messages can be output properly
594 gchar const *charset;
595 g_get_charset(&charset);
597 bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
599 poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
600 poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
601 g_return_val_if_fail(ctx != NULL, 1);
603 /* Collect own arguments */
604 GSList *fl = sp_process_args(ctx);
605 poptFreeContext(ctx);
607 // now switch gettext back to UTF-8 (for GUI)
608 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
610 // Now let's see if the file list still holds up
611 if ( needToRecodeParams )
612 {
613 fl = fixupFilenameEncoding( fl );
614 }
616 // Check the globals for filename-fixup
617 if ( needToRecodeParams )
618 {
619 fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
620 fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
621 fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
622 }
623 else
624 {
625 if ( sp_export_png )
626 sp_export_png_utf8 = g_strdup( sp_export_png );
627 if ( sp_export_svg )
628 sp_export_svg_utf8 = g_strdup( sp_export_svg );
629 if ( sp_global_printer )
630 sp_global_printer_utf8 = g_strdup( sp_global_printer );
631 }
633 // Return the list if wanted, else free it up.
634 if ( flDest ) {
635 *flDest = fl;
636 fl = 0;
637 } else {
638 while ( fl ) {
639 g_free( fl->data );
640 fl = g_slist_remove( fl, fl->data );
641 }
642 }
643 return 0;
644 }
646 static void
647 snooper(GdkEvent *event, gpointer /*data*/) {
648 if(inkscape_mapalt()) /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
649 {
650 GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
651 switch (event->type) {
652 case GDK_MOTION_NOTIFY:
653 if(event->motion.state & mapping) {
654 event->motion.state|=GDK_MOD1_MASK;
655 }
656 break;
657 case GDK_BUTTON_PRESS:
658 if(event->button.state & mapping) {
659 event->button.state|=GDK_MOD1_MASK;
660 }
661 break;
662 case GDK_KEY_PRESS:
663 if(event->key.state & mapping) {
664 event->key.state|=GDK_MOD1_MASK;
665 }
666 break;
667 default:
668 break;
669 }
670 }
671 gtk_main_do_event (event);
672 }
674 int
675 sp_main_gui(int argc, char const **argv)
676 {
677 Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
679 GSList *fl = NULL;
680 int retVal = sp_common_main( argc, argv, &fl );
681 g_return_val_if_fail(retVal == 0, 1);
683 inkscape_gtk_stock_init();
685 gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
687 Inkscape::Debug::log_display_config();
689 /* Set default icon */
690 gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
691 if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
692 gtk_window_set_default_icon_from_file(filename, NULL);
693 }
694 g_free (filename);
695 filename = 0;
697 gboolean create_new = TRUE;
699 /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
700 inkscape_application_init(argv[0], true);
702 while (fl) {
703 if (sp_file_open((gchar *)fl->data,NULL)) {
704 create_new=FALSE;
705 }
706 fl = g_slist_remove(fl, fl->data);
707 }
708 if (create_new) {
709 sp_file_new_default();
710 }
712 Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
713 main_instance.run();
715 #ifdef WIN32
716 //We might not need anything here
717 //sp_win32_finish(); <-- this is a NOP func
718 #endif
720 return 0;
721 }
723 int
724 sp_main_console(int argc, char const **argv)
725 {
726 /* We are started in text mode */
728 /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
729 * in a non-Gtk environment. Used in libnrtype's
730 * FontInstance.cpp and FontFactory.cpp.
731 * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
732 */
733 g_type_init();
734 char **argv2 = const_cast<char **>(argv);
735 gtk_init_check( &argc, &argv2 );
736 //setlocale(LC_ALL, "");
738 GSList *fl = NULL;
739 int retVal = sp_common_main( argc, argv, &fl );
740 g_return_val_if_fail(retVal == 0, 1);
742 if (fl == NULL) {
743 g_print("Nothing to do!\n");
744 exit(0);
745 }
747 inkscape_application_init(argv[0], false);
749 while (fl) {
750 SPDocument *doc;
752 doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
753 if (doc == NULL) {
754 doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
755 }
756 if (doc == NULL) {
757 g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
758 } else {
759 if (sp_vacuum_defs) {
760 vacuum_document(doc);
761 }
762 if (sp_vacuum_defs && !sp_export_svg) {
763 // save under the name given in the command line
764 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
765 }
766 if (sp_global_printer) {
767 sp_print_document_to_file(doc, sp_global_printer);
768 }
769 if (sp_export_png || sp_export_id || sp_export_area_drawing) {
770 sp_do_export_png(doc);
771 }
772 if (sp_export_svg) {
773 Inkscape::XML::Document *rdoc;
774 Inkscape::XML::Node *repr;
775 rdoc = sp_repr_document_new("svg:svg");
776 repr = rdoc->root();
777 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
778 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
779 }
780 if (sp_export_ps) {
781 do_export_ps(doc, sp_export_ps, "image/x-postscript");
782 }
783 if (sp_export_eps) {
784 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
785 }
786 if (sp_export_pdf) {
787 do_export_pdf(doc, sp_export_pdf, "application/pdf");
788 }
789 #ifdef WIN32
790 if (sp_export_emf) {
791 do_export_emf(doc, sp_export_emf, "image/x-emf");
792 }
793 #endif //WIN32
794 if (sp_query_width || sp_query_height) {
795 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
796 } else if (sp_query_x || sp_query_y) {
797 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
798 }
799 }
801 fl = g_slist_remove(fl, fl->data);
802 }
804 inkscape_unref();
806 return 0;
807 }
809 static void
810 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
811 {
812 SPObject *o = NULL;
814 if (id) {
815 o = doc->getObjectById(id);
816 if (o) {
817 if (!SP_IS_ITEM (o)) {
818 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
819 return;
820 }
821 } else {
822 g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
823 return;
824 }
825 } else {
826 o = SP_DOCUMENT_ROOT(doc);
827 }
829 if (o) {
830 sp_document_ensure_up_to_date (doc);
831 SPItem *item = ((SPItem *) o);
833 // "true" SVG bbox for scripting
834 NR::Maybe<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
835 if (area) {
836 Inkscape::SVGOStringStream os;
837 if (extent) {
838 os << area->extent(axis);
839 } else {
840 os << area->min()[axis];
841 }
842 g_print ("%s", os.str().c_str());
843 } else {
844 g_print("0");
845 }
846 }
847 }
850 static void
851 sp_do_export_png(SPDocument *doc)
852 {
853 const gchar *filename = NULL;
854 gdouble dpi = 0.0;
856 if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
857 g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
858 }
860 GSList *items = NULL;
862 NRRect area;
863 if (sp_export_id || sp_export_area_drawing) {
865 SPObject *o = NULL;
866 SPObject *o_area = NULL;
867 if (sp_export_id && sp_export_area_drawing) {
868 o = doc->getObjectById(sp_export_id);
869 o_area = SP_DOCUMENT_ROOT (doc);
870 } else if (sp_export_id) {
871 o = doc->getObjectById(sp_export_id);
872 o_area = o;
873 } else if (sp_export_area_drawing) {
874 o = SP_DOCUMENT_ROOT (doc);
875 o_area = o;
876 }
878 if (o) {
879 if (!SP_IS_ITEM (o)) {
880 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
881 return;
882 }
884 items = g_slist_prepend (items, SP_ITEM(o));
886 if (sp_export_id_only) {
887 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
888 }
890 if (sp_export_use_hints) {
892 // retrieve export filename hint
893 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
894 if (fn_hint) {
895 if (sp_export_png) {
896 g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
897 filename = sp_export_png;
898 } else {
899 filename = fn_hint;
900 }
901 } else {
902 g_warning ("Export filename hint not found for the object.");
903 filename = sp_export_png;
904 }
906 // retrieve export dpi hints
907 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
908 if (dpi_hint) {
909 if (sp_export_dpi || sp_export_width || sp_export_height) {
910 g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
911 } else {
912 dpi = atof(dpi_hint);
913 }
914 } else {
915 g_warning ("Export DPI hint not found for the object.");
916 }
918 }
920 // write object bbox to area
921 sp_document_ensure_up_to_date (doc);
922 sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
923 } else {
924 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
925 return;
926 }
927 }
929 if (sp_export_area) {
930 /* Try to parse area (given in SVG pixels) */
931 if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
932 g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
933 return;
934 }
935 if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
936 g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
937 return;
938 }
939 } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
940 /* Export the whole canvas */
941 sp_document_ensure_up_to_date (doc);
942 area.x0 = SP_ROOT(doc->root)->x.computed;
943 area.y0 = SP_ROOT(doc->root)->y.computed;
944 area.x1 = area.x0 + sp_document_width (doc);
945 area.y1 = area.y0 + sp_document_height (doc);
946 }
948 // set filename and dpi from options, if not yet set from the hints
949 if (!filename) {
950 if (!sp_export_png) {
951 g_warning ("No export filename given and no filename hint. Nothing exported.");
952 return;
953 }
954 filename = sp_export_png;
955 }
957 if (sp_export_dpi && dpi == 0.0) {
958 dpi = atof(sp_export_dpi);
959 if ((dpi < 0.1) || (dpi > 10000.0)) {
960 g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
961 return;
962 }
963 g_print("DPI: %g\n", dpi);
964 }
966 if (sp_export_area_snap) {
967 area.x0 = std::floor (area.x0);
968 area.y0 = std::floor (area.y0);
969 area.x1 = std::ceil (area.x1);
970 area.y1 = std::ceil (area.y1);
971 }
973 // default dpi
974 if (dpi == 0.0)
975 dpi = PX_PER_IN;
977 unsigned long int width = 0;
978 unsigned long int height = 0;
980 if (sp_export_width) {
981 width = strtoul(sp_export_width, NULL, 0);
982 if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
983 g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
984 return;
985 }
986 dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
987 }
989 if (sp_export_height) {
990 height = strtoul(sp_export_height, NULL, 0);
991 if ((height < 1) || (height > PNG_UINT_31_MAX)) {
992 g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
993 return;
994 }
995 dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
996 }
998 if (!sp_export_width) {
999 width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1000 }
1002 if (!sp_export_height) {
1003 height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1004 }
1006 guint32 bgcolor = 0x00000000;
1007 if (sp_export_background) {
1008 // override the page color
1009 bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1010 bgcolor |= 0xff; // default is no opacity
1011 } else {
1012 // read from namedview
1013 Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1014 if (nv && nv->attribute("pagecolor"))
1015 bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1016 if (nv && nv->attribute("inkscape:pageopacity"))
1017 bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1018 }
1020 if (sp_export_background_opacity) {
1021 // override opacity
1022 gfloat value;
1023 if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1024 if (value > 1.0) {
1025 value = CLAMP (value, 1.0f, 255.0f);
1026 bgcolor &= (guint32) 0xffffff00;
1027 bgcolor |= (guint32) floor(value);
1028 } else {
1029 value = CLAMP (value, 0.0f, 1.0f);
1030 bgcolor &= (guint32) 0xffffff00;
1031 bgcolor |= SP_COLOR_F_TO_U(value);
1032 }
1033 }
1034 }
1036 g_print("Background RRGGBBAA: %08x\n", bgcolor);
1038 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);
1040 g_print("Bitmap saved as: %s\n", filename);
1042 if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1043 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);
1044 } else {
1045 g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1046 }
1048 g_slist_free (items);
1049 }
1052 /**
1053 * Perform an export of either PS or EPS.
1054 *
1055 * \param doc Document to export.
1056 * \param uri URI to export to.
1057 * \param mime MIME type to export as.
1058 */
1060 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1061 {
1062 Inkscape::Extension::DB::OutputList o;
1063 Inkscape::Extension::db.get_output_list(o);
1064 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1065 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1066 i++;
1067 }
1069 if (i == o.end())
1070 {
1071 g_warning ("Could not find an extension to export this file.");
1072 return;
1073 }
1075 bool old_text_to_path = false;
1076 bool old_font_embedded = false;
1077 bool old_bbox_page = false;
1079 try {
1080 old_text_to_path = (*i)->get_param_bool("textToPath");
1081 (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1082 }
1083 catch (...) {
1084 g_warning ("Could not set export-text-to-path option for this export.");
1085 }
1087 try {
1088 old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1089 (*i)->set_param_bool("fontEmbedded", sp_export_font);
1090 }
1091 catch (...) {
1092 g_warning ("Could not set export-font option for this export.");
1093 }
1095 try {
1096 old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1097 (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1098 }
1099 catch (...) {
1100 g_warning ("Could not set export-bbox-page option for this export.");
1101 }
1103 (*i)->save(doc, uri);
1105 try {
1106 (*i)->set_param_bool("textToPath", old_text_to_path);
1107 (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1108 (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1109 }
1110 catch (...) {
1112 }
1113 }
1115 /**
1116 * Perform a PDF export
1117 *
1118 * \param doc Document to export.
1119 * \param uri URI to export to.
1120 * \param mime MIME type to export as.
1121 */
1123 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1124 {
1125 Inkscape::Extension::DB::OutputList o;
1126 Inkscape::Extension::db.get_output_list(o);
1127 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1128 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1129 i++;
1130 }
1132 if (i == o.end())
1133 {
1134 g_warning ("Could not find an extension to export this file.");
1135 return;
1136 }
1138 (*i)->save(doc, uri);
1139 }
1141 #ifdef WIN32
1142 /**
1143 * Export a document to EMF
1144 *
1145 * \param doc Document to export.
1146 * \param uri URI to export to.
1147 * \param mime MIME type to export as (should be "image/x-emf")
1148 */
1150 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1151 {
1152 Inkscape::Extension::DB::OutputList o;
1153 Inkscape::Extension::db.get_output_list(o);
1154 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1155 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1156 i++;
1157 }
1159 if (i == o.end())
1160 {
1161 g_warning ("Could not find an extension to export this file.");
1162 return;
1163 }
1165 (*i)->save(doc, uri);
1166 }
1167 #endif //WIN32
1169 #ifdef WIN32
1170 bool replaceArgs( int& argc, char**& argv )
1171 {
1172 bool worked = false;
1174 #ifdef REPLACEARGS_DEBUG
1175 MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1176 #endif // REPLACEARGS_DEBUG
1178 wchar_t* line = GetCommandLineW();
1179 if ( line )
1180 {
1181 #ifdef REPLACEARGS_DEBUG
1182 {
1183 gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1184 if ( utf8Line )
1185 {
1186 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1187 {
1188 char tmp[strlen(safe) + 32];
1189 snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1190 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1191 }
1192 }
1193 }
1194 #endif // REPLACEARGS_DEBUG
1196 int numArgs = 0;
1197 wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1199 #ifdef REPLACEARGS_ANSI
1200 // test code for trying things on Win95/98/ME
1201 if ( !parsed )
1202 {
1203 #ifdef REPLACEARGS_DEBUG
1204 MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1205 #endif // REPLACEARGS_DEBUG
1206 int lineLen = wcslen(line) + 1;
1207 wchar_t* lineDup = new wchar_t[lineLen];
1208 wcsncpy( lineDup, line, lineLen );
1210 int pos = 0;
1211 bool inQuotes = false;
1212 bool inWhitespace = true;
1213 std::vector<int> places;
1214 while ( lineDup[pos] )
1215 {
1216 if ( inQuotes )
1217 {
1218 if ( lineDup[pos] == L'"' )
1219 {
1220 inQuotes = false;
1221 }
1222 }
1223 else if ( lineDup[pos] == L'"' )
1224 {
1225 inQuotes = true;
1226 inWhitespace = false;
1227 places.push_back(pos);
1228 }
1229 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1230 {
1231 if ( !inWhitespace )
1232 {
1233 inWhitespace = true;
1234 lineDup[pos] = 0;
1235 }
1236 }
1237 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1238 {
1239 inWhitespace = false;
1240 places.push_back(pos);
1241 }
1242 else
1243 {
1244 // consume
1245 }
1246 pos++;
1247 }
1248 #ifdef REPLACEARGS_DEBUG
1249 {
1250 char tmp[256];
1251 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1252 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1253 }
1254 #endif // REPLACEARGS_DEBUG
1256 wchar_t** block = new wchar_t*[places.size()];
1257 int i = 0;
1258 for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1259 {
1260 block[i++] = &lineDup[*it];
1261 }
1262 parsed = block;
1263 numArgs = places.size();
1264 }
1265 #endif // REPLACEARGS_ANSI
1267 if ( parsed )
1268 {
1269 std::vector<wchar_t*>expandedArgs;
1270 if ( numArgs > 0 )
1271 {
1272 expandedArgs.push_back( parsed[0] );
1273 }
1275 for ( int i1 = 1; i1 < numArgs; i1++ )
1276 {
1277 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1278 wildcarded &= parsed[i1][0] != L'"';
1279 wildcarded &= parsed[i1][0] != L'-';
1280 if ( wildcarded )
1281 {
1282 #ifdef REPLACEARGS_ANSI
1283 WIN32_FIND_DATAA data = {0};
1284 #else
1285 WIN32_FIND_DATAW data = {0};
1286 #endif // REPLACEARGS_ANSI
1288 int baseLen = wcslen(parsed[i1]) + 2;
1289 wchar_t* base = new wchar_t[baseLen];
1290 wcsncpy( base, parsed[i1], baseLen );
1291 wchar_t* last = wcsrchr( base, L'\\' );
1292 if ( last )
1293 {
1294 last[1] = 0;
1295 }
1296 else
1297 {
1298 base[0] = 0;
1299 }
1300 baseLen = wcslen( base );
1302 #ifdef REPLACEARGS_ANSI
1303 char target[MAX_PATH];
1304 if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1305 {
1306 HANDLE hf = FindFirstFileA( target, &data );
1307 #else
1308 HANDLE hf = FindFirstFileW( parsed[i1], &data );
1309 #endif // REPLACEARGS_ANSI
1310 if ( hf != INVALID_HANDLE_VALUE )
1311 {
1312 BOOL found = TRUE;
1313 do
1314 {
1315 #ifdef REPLACEARGS_ANSI
1316 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1317 if ( howMany > 0 )
1318 {
1319 howMany += baseLen;
1320 wchar_t* tmp = new wchar_t[howMany + 1];
1321 wcsncpy( tmp, base, howMany + 1 );
1322 MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1323 expandedArgs.push_back( tmp );
1324 found = FindNextFileA( hf, &data );
1325 }
1326 #else
1327 int howMany = wcslen(data.cFileName) + baseLen;
1328 wchar_t* tmp = new wchar_t[howMany + 1];
1329 wcsncpy( tmp, base, howMany + 1 );
1330 wcsncat( tmp, data.cFileName, howMany + 1 );
1331 expandedArgs.push_back( tmp );
1332 found = FindNextFileW( hf, &data );
1333 #endif // REPLACEARGS_ANSI
1334 } while ( found );
1336 FindClose( hf );
1337 }
1338 else
1339 {
1340 expandedArgs.push_back( parsed[i1] );
1341 }
1342 #ifdef REPLACEARGS_ANSI
1343 }
1344 #endif // REPLACEARGS_ANSI
1346 delete[] base;
1347 }
1348 else
1349 {
1350 expandedArgs.push_back( parsed[i1] );
1351 }
1352 }
1354 {
1355 wchar_t** block = new wchar_t*[expandedArgs.size()];
1356 int iz = 0;
1357 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1358 {
1359 block[iz++] = *it;
1360 }
1361 parsed = block;
1362 numArgs = expandedArgs.size();
1363 }
1365 std::vector<gchar*> newArgs;
1366 for ( int i = 0; i < numArgs; i++ )
1367 {
1368 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1369 if ( replacement )
1370 {
1371 #ifdef REPLACEARGS_DEBUG
1372 gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1374 if ( safe2 )
1375 {
1376 {
1377 char tmp[1024];
1378 snprintf( tmp, sizeof(tmp), " [%2d] = '%s'", i, safe2 );
1379 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1380 }
1381 g_free( safe2 );
1382 }
1383 #endif // REPLACEARGS_DEBUG
1385 newArgs.push_back( replacement );
1386 }
1387 else
1388 {
1389 newArgs.push_back( blankParam );
1390 }
1391 }
1393 // Now push our munged params to be the new argv and argc
1394 {
1395 char** block = new char*[newArgs.size()];
1396 int iz = 0;
1397 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1398 {
1399 block[iz++] = *it;
1400 }
1401 argv = block;
1402 argc = newArgs.size();
1403 worked = true;
1404 }
1405 }
1406 #ifdef REPLACEARGS_DEBUG
1407 else
1408 {
1409 MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1410 }
1411 #endif // REPLACEARGS_DEBUG
1412 }
1413 #ifdef REPLACEARGS_DEBUG
1414 else
1415 {
1416 {
1417 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1418 }
1420 char* line2 = GetCommandLineA();
1421 if ( line2 )
1422 {
1423 gchar *safe = Inkscape::IO::sanitizeString(line2);
1424 {
1425 {
1426 char tmp[strlen(safe) + 32];
1427 snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1428 MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1429 }
1430 }
1431 }
1432 else
1433 {
1434 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1435 }
1436 }
1437 #endif // REPLACEARGS_DEBUG
1439 return worked;
1440 }
1441 #endif // WIN32
1443 static GSList *
1444 sp_process_args(poptContext ctx)
1445 {
1446 GSList *fl = NULL;
1448 gint a;
1449 while ((a = poptGetNextOpt(ctx)) >= 0) {
1450 switch (a) {
1451 case SP_ARG_FILE: {
1452 gchar const *fn = poptGetOptArg(ctx);
1453 if (fn != NULL) {
1454 fl = g_slist_append(fl, g_strdup(fn));
1455 }
1456 break;
1457 }
1458 case SP_ARG_VERSION: {
1459 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1460 exit(0);
1461 break;
1462 }
1463 case SP_ARG_EXTENSIONDIR: {
1464 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1465 exit(0);
1466 break;
1467 }
1468 case SP_ARG_VERB_LIST: {
1469 // This really shouldn't go here, we should init the app.
1470 // But, since we're just exiting in this path, there is
1471 // no harm, and this is really a better place to put
1472 // everything else.
1473 Inkscape::Extension::init();
1474 Inkscape::Verb::list();
1475 exit(0);
1476 break;
1477 }
1478 case SP_ARG_VERB:
1479 case SP_ARG_SELECT: {
1480 gchar const *arg = poptGetOptArg(ctx);
1481 if (arg != NULL) {
1482 // printf("Adding in: %s\n", arg);
1483 new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1484 }
1485 break;
1486 }
1487 default: {
1488 break;
1489 }
1490 }
1491 }
1493 gchar const ** const args = poptGetArgs(ctx);
1494 if (args != NULL) {
1495 for (unsigned i = 0; args[i] != NULL; i++) {
1496 fl = g_slist_append(fl, g_strdup(args[i]));
1497 }
1498 }
1500 return fl;
1501 }
1504 /*
1505 Local Variables:
1506 mode:c++
1507 c-file-style:"stroustrup"
1508 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1509 indent-tabs-mode:nil
1510 fill-column:99
1511 End:
1512 */
1513 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :