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