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