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